home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / mamedbg.c < prev    next >
C/C++ Source or Header  |  2000-05-20  |  149KB  |  5,300 lines

  1. /****************************************************************************
  2.  *    The new MAME debugger V0.53
  3.  *    Written by:   Juergen Buchmueller (so far - help welcome! :)
  4.  *
  5.  *    Based on code found in the preivous version of the MAME debugger
  6.  *    written by:   Martin Scragg, John Butler, Mirko Buffoni
  7.  *                  Chris Moore, Aaron Giles, Ernesto Corvi
  8.  *
  9.  *  Online help is available by pressing F1 (context sensitive!)
  10.  *
  11.  *    TODO:
  12.  *    - Verify correct endianess handling, ie. look at the word and dword
  13.  *      modes of the memory and disassembly windows (selected with M)
  14.  *    - Squash thousands of bugs :-/
  15.  *    - Test & improve name_rom()
  16.  *    - Add more names for generic handlers to name_rdmem() and name_wrmem()
  17.  *
  18.  *  LATER:
  19.  *    - Add stack view using cpu_get_reg(REG_SP_CONTENTS+offset)
  20.  *    - Add more display modes for the memory windows (binary? octal? decimal?)
  21.  *    - Make the windows resizeable somehow (using win_set_w and win_set_h)
  22.  *    - Anything you like - just contact me to avoid doubled effort.
  23.  *
  24.  ****************************************************************************/
  25.  
  26. #include <stdio.h>
  27.  
  28. #ifdef MAME_DEBUG
  29. #include "mamedbg.h"
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <stdarg.h>
  33. #include <ctype.h>
  34. #include "driver.h"
  35. #include "window.h"
  36. #include "vidhrdw/generic.h"
  37. #include "osd_dbg.h"
  38.  
  39.  
  40. #if (HAS_Z80)
  41. #include "cpu/z80/z80.h"
  42. #endif
  43. #if (HAS_8080 || HAS_8085A)
  44. #include "cpu/i8085/i8085.h"
  45. #endif
  46. #if (HAS_M6502 || HAS_M65C02 || HAS_M65SC02 || HAS_M6510 || HAS_M6510T || HAS_M7501 || HAS_M8502 || HAS_N2A03)
  47. #include "cpu/m6502/m6502.h"
  48. #endif
  49. #if (HAS_M4510)
  50. #include "cpu/m6502/m4510.h"
  51. #endif
  52. #if (HAS_M65CE02)
  53. #include "cpu/m6502/m65ce02.h"
  54. #endif
  55. #if (HAS_M6509)
  56. #include "cpu/m6502/m6509.h"
  57. #endif
  58. #if (HAS_H6280)
  59. #include "cpu/h6280/h6280.h"
  60. #endif
  61. #if (HAS_I86)
  62. #include "cpu/i86/i86intf.h"
  63. #endif
  64. #if (HAS_I88)
  65. #include "cpu/i86/i88intf.h"
  66. #endif
  67. #if (HAS_I186)
  68. #include "cpu/i86/i186intf.h"
  69. #endif
  70. #if (HAS_I188)
  71. #include "cpu/i86/i188intf.h"
  72. #endif
  73. #if (HAS_I286)
  74. #include "cpu/i86/i286intf.h"
  75. #endif
  76. #if (HAS_V20 || HAS_V30 || HAS_V33)
  77. #include "cpu/nec/necintrf.h"
  78. #endif
  79. #if (HAS_I8035 || HAS_I8039 || HAS_I8048 || HAS_N7751)
  80. #include "cpu/i8039/i8039.h"
  81. #endif
  82. #if (HAS_M6800 || HAS_M6801 || HAS_M6802 || HAS_M6803 || HAS_M6808 || HAS_HD63701)
  83. #include "cpu/m6800/m6800.h"
  84. #endif
  85. #if (HAS_M6805 || HAS_M68705 || HAS_HD63705)
  86. #include "cpu/m6805/m6805.h"
  87. #endif
  88. #if (HAS_HD6309 || HAS_M6809)
  89. #include "cpu/m6809/m6809.h"
  90. #endif
  91. #if (HAS_M68000 || defined HAS_M68010 || HAS_M68020)
  92. #include "cpu/m68000/m68000.h"
  93. #endif
  94. #if (HAS_T11)
  95. #include "cpu/t11/t11.h"
  96. #endif
  97. #if (HAS_S2650)
  98. #include "cpu/s2650/s2650.h"
  99. #endif
  100. #if (HAS_TMS34010)
  101. #include "cpu/tms34010/tms34010.h"
  102. #endif
  103. #if (HAS_TMS9900) || (HAS_TMS9940) || (HAS_TMS9980) || (HAS_TMS9985) \
  104.         || (HAS_TMS9989) || (HAS_TMS9995) || (HAS_TMS99105A) || (HAS_TMS99110A)
  105. #include "cpu/tms9900/tms9900.h"
  106. #endif
  107. #if (HAS_Z8000)
  108. #include "cpu/z8000/z8000.h"
  109. #endif
  110. #if (HAS_TMS320C10)
  111. #include "cpu/tms32010/tms32010.h"
  112. #endif
  113. #if (HAS_CCPU)
  114. #include "cpu/ccpu/ccpu.h"
  115. #endif
  116. #if (HAS_PDP1)
  117. #include "cpu/pdp1/pdp1.h"
  118. #endif
  119.  
  120. #ifndef INVALID
  121. #define INVALID -1
  122. #endif
  123.  
  124. /****************************************************************************
  125.  * Externals (define in the header files)
  126.  ****************************************************************************/
  127. /* Long(er) function names, short macro names... */
  128. #define ABITS    cpu_address_bits()
  129. #define AMASK   cpu_address_mask()
  130. #define ASHIFT    cpu_address_shift()
  131. #define ALIGN   cpu_align_unit()
  132. #define INSTL   cpu_max_inst_len()
  133. #define ENDIAN    cpu_endianess()
  134.  
  135. #define RDMEM(a)    (*cpuintf[cputype].memory_read)(a)
  136. #define WRMEM(a,v)    (*cpuintf[cputype].memory_write)(a,v)
  137.  
  138. /****************************************************************************
  139.  * Globals
  140.  ****************************************************************************/
  141. int debug_key_pressed = 0;
  142. int debug_key_delay = 0;
  143.  
  144. /****************************************************************************
  145.  * Limits
  146.  ****************************************************************************/
  147. #define MAX_DATA    512         /* Maximum memory size in bytes of a dump window */
  148. #define MAX_MEM     2            /* You can't redefine this... too easy */
  149.  
  150. #define MAX_LOOPS    64            /* Maximum loop addresses recognized by trace */
  151.  
  152. #define MAX_HIST    16            /* Maximum history depth */
  153.  
  154. #define EDIT_CMDS   0
  155. #define EDIT_REGS    1            /* Just the order of the windows */
  156. #define EDIT_DASM    2
  157. #define EDIT_MEM1    3
  158. #define EDIT_MEM2    4
  159.  
  160. #define DBG_WINDOWS 5
  161.  
  162. /* Some convenience macros to address the cpu'th window */
  163. #define WIN_CMDS(cpu)   (cpu*DBG_WINDOWS+EDIT_CMDS)
  164. #define WIN_REGS(cpu)    (cpu*DBG_WINDOWS+EDIT_REGS)
  165. #define WIN_DASM(cpu)    (cpu*DBG_WINDOWS+EDIT_DASM)
  166. #define WIN_MEM(cpu,n)    (cpu*DBG_WINDOWS+EDIT_MEM1+n)
  167. #define WIN_MEM1(cpu)    (cpu*DBG_WINDOWS+EDIT_MEM1)
  168. #define WIN_MEM2(cpu)    (cpu*DBG_WINDOWS+EDIT_MEM2)
  169. #define WIN_HELP        (MAX_WINDOWS-1)
  170. #define WIN_MSGBOX        (MAX_WINDOWS-2)
  171.  
  172. #define MODE_HEX_UINT8    0
  173. #define MODE_HEX_UINT16 1
  174. #define MODE_HEX_UINT32 2
  175.  
  176. #define UINT16_XOR_LE(o) (((o)&~1)|(((o)&1)^1))
  177. #define UINT32_XOR_LE(o) (((o)&~3)|(((o)&3)^3))
  178. #define HOST_XOR_LE  0
  179. #define UINT16_XOR_BE(o) (o)
  180. #define UINT32_XOR_BE(o) (o)
  181. #define HOST_XOR_BE  0
  182.  
  183. /****************************************************************************
  184.  * Statics
  185.  ****************************************************************************/
  186. static int first_time = 1;
  187.  
  188. static int activecpu = INVALID;
  189. static int previous_activecpu = INVALID;
  190. static int totalcpu = 0;
  191. static int cputype = 0;
  192.  
  193. static int dbg_fast = 0;
  194. static int dbg_step = 0;
  195. static int dbg_trace = 0;
  196. static int dbg_trace_delay = 0x1000;
  197. static int dbg_update = 0;
  198. static int dbg_update_cur = 0;
  199. static int dbg_active = 0;
  200.  
  201. /* 0 = dont, 1 = do allow squeezed display w/alternating dim, bright colors */
  202. static int dbg_mem_squeezed = 0;
  203. /* 0 = display disassembly only, 1 = display opcodes too */
  204. static int dbg_dasm_opcodes = 0;
  205. /* 0 = default, 1 = lower or 2 = upper case */
  206. static int dbg_dasm_case = 0;
  207. /* 0 = absolute, 1 = relative format for relative jumps/branches */
  208. static int dbg_dasm_relative_jumps = 0;
  209.  
  210. static const char *dbg_info_once = NULL;
  211.  
  212. /****************************************************************************
  213.  * Color settings
  214.  ****************************************************************************/
  215. #define COLOR_NAMES \
  216.     "BLACK\0" \
  217.     "BLUE\0" \
  218.     "GREEN\0" \
  219.     "CYAN\0" \
  220.     "RED\0" \
  221.     "MAGENTA\0" \
  222.     "BROWN\0" \
  223.     "LIGHTGRAY\0" \
  224.     "DARKGRAY\0" \
  225.     "LIGHTBLUE\0" \
  226.     "LIGHTGREEN\0" \
  227.     "LIGHTCYAN\0" \
  228.     "LIGHTRED\0" \
  229.     "LIGHTMAGENTA\0" \
  230.     "YELLOW\0" \
  231.     "WHITE\0"
  232.  
  233. #define ELEMENT_NAMES \
  234.     "TITLE\0" \
  235.     "FRAME\0" \
  236.     "REGS\0" \
  237.     "DASM\0" \
  238.     "MEM1\0" \
  239.     "MEM2\0" \
  240.     "CMDS\0" \
  241.     "BRK_EXEC\0" \
  242.     "BRK_DATA\0" \
  243.     "BRK_REGS\0" \
  244.     "ERROR\0" \
  245.     "HELP\0" \
  246.     "PROMPT\0" \
  247.     "CHANGES\0" \
  248.     "PC\0" \
  249.     "CURSOR\0"
  250.  
  251. enum ELEMENT {
  252.     E_TITLE,
  253.     E_FRAME,
  254.     E_REGS,
  255.     E_DASM,
  256.     E_MEM1,
  257.     E_MEM2,
  258.     E_CMDS,
  259.     E_BRK_EXEC,
  260.     E_BRK_DATA,
  261.     E_BRK_REGS,
  262.     E_ERROR,
  263.     E_HELP,
  264.     E_PROMPT,
  265.     E_CHANGES,
  266.     E_PC,
  267.     E_CURSOR,
  268.     E_COUNT
  269. };
  270.  
  271. static UINT8 cur_col[E_COUNT] = {
  272.     COLOR_TITLE,
  273.     COLOR_FRAME,
  274.     COLOR_REGS,
  275.     COLOR_DASM,
  276.     COLOR_MEM1,
  277.     COLOR_MEM2,
  278.     COLOR_CMDS,
  279.     COLOR_BRK_EXEC,
  280.     COLOR_BRK_DATA,
  281.     COLOR_BRK_REGS,
  282.     COLOR_ERROR,
  283.     COLOR_HELP,
  284.     COLOR_PROMPT,
  285.     COLOR_CHANGES,
  286.     COLOR_PC,
  287.     COLOR_CURSOR,
  288. };
  289.  
  290. static UINT8 def_col[E_COUNT] = {
  291.     COLOR_TITLE,
  292.     COLOR_FRAME,
  293.     COLOR_REGS,
  294.     COLOR_DASM,
  295.     COLOR_MEM1,
  296.     COLOR_MEM2,
  297.     COLOR_CMDS,
  298.     COLOR_BRK_EXEC,
  299.     COLOR_BRK_DATA,
  300.     COLOR_BRK_REGS,
  301.     COLOR_ERROR,
  302.     COLOR_HELP,
  303.     COLOR_PROMPT,
  304.     COLOR_CHANGES,
  305.     COLOR_PC,
  306.     COLOR_CURSOR,
  307. };
  308.  
  309. /****************************************************************************
  310.  * Code to ASCII translation table; may be redefined (later)
  311.  ****************************************************************************/
  312. static char trans_table[256] = {
  313.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  314.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  315.     ' ','!','"','#','$','%','&', 39,'(',')','*','+',',','-','.','/',
  316.     '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
  317.     '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
  318.     'P','Q','R','S','T','U','V','W','X','Y','Z','[', 92,']','^','_',
  319.     '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
  320.     'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~','.',
  321.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  322.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  323.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  324.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  325.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  326.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  327.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  328.     '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
  329. };
  330.  
  331. /****************************************************************************
  332.  * Function prototypes
  333.  ****************************************************************************/
  334. static unsigned get_register_id( char **parg, int *size );
  335. static const char *get_register_name( int id );
  336. static unsigned get_register_or_value( char **parg, int *size );
  337. static void trace_init( const char *filename, UINT8 *regs );
  338. static void trace_done( void );
  339. static void trace_select( void );
  340. static void trace_output( void );
  341.  
  342. static int hit_brk_exec( void );
  343. static int hit_brk_data( void );
  344. static int hit_brk_regs( void );
  345.  
  346. static const char *name_rom( const char *type, int region, unsigned *base, unsigned start );
  347. static const char *name_rdmem( unsigned base );
  348. static const char *name_wrmem( unsigned base );
  349. static const char *name_memory( unsigned base );
  350.  
  351. static int win_create(int n, UINT8 prio, int x, int y, int w, int h,
  352.     UINT8 co_text, UINT8 co_frame, UINT8 chr, UINT32 attributes);
  353. static int DECL_SPEC win_msgbox( UINT8 color, const char *title, const char *fmt, ... );
  354. static void dbg_open_windows( void );
  355. static void dbg_close_windows( void );
  356.  
  357. static unsigned dasm_line( unsigned pc, int times );
  358.  
  359. static void dump_regs( void );
  360. static unsigned dump_dasm( unsigned pc );
  361. static void dump_mem_hex( int which, unsigned len_addr, unsigned len_data );
  362. static void dump_mem( int which, int set_title );
  363.  
  364. static int edit_cmds_info( void );
  365. static int edit_cmds_parse( char *cmdline );
  366. static void edit_cmds_append( const char *src );
  367.  
  368. static void edit_regs( void );
  369. static void edit_dasm( void );
  370. static void edit_mem( int which );
  371. static void edit_cmds(void);
  372.  
  373. static void cmd_help( void );
  374. static void cmd_default( int code );
  375.  
  376. static void cmd_display_memory( void );
  377. static void cmd_edit_memory( void );
  378. static void cmd_set_memory_mode( void );
  379. static void cmd_fast( void );
  380. static void cmd_go_break( void );
  381. static void cmd_jump( void );
  382. static void cmd_replace_register( void );
  383. static void cmd_brk_exec_set( void );
  384. static void cmd_brk_exec_clear( void );
  385. static void cmd_brk_regs_set( void );
  386. static void cmd_brk_regs_clear( void );
  387. static void cmd_brk_data_set( void );
  388. static void cmd_brk_data_clear( void );
  389. static void cmd_here( void );
  390. static void cmd_dasm_to_file( void );
  391. static void cmd_dump_to_file( void );
  392. static void cmd_trace_to_file( void );
  393. static void cmd_save_to_file( void );
  394. static void cmd_set_ignore( void );
  395. static void cmd_set_observe( void );
  396. static void cmd_set_dasm_case( void );
  397. static void cmd_set_dasm_opcodes( void );
  398. static void cmd_set_dasm_relative_jumps( void );
  399. static void cmd_set_mem_squeezed( void );
  400. static void cmd_set_screen_size( void );
  401. static void cmd_set_element_color( void );
  402. static void cmd_brk_exec_toggle( void );
  403. static void cmd_brk_data_toggle( void );
  404.  
  405. static void cmd_switch_window( void );
  406. static void cmd_dasm_up( void );
  407. static void cmd_dasm_down( void );
  408. static void cmd_dasm_page_up( void );
  409. static void cmd_dasm_page_down( void );
  410. static void cmd_dasm_home( void );
  411. static void cmd_dasm_end( void );
  412. static void cmd_dasm_hist_follow( void );
  413. static void cmd_dasm_hist_back( void );
  414. static void cmd_run_to_cursor( void );
  415. static void cmd_view_screen( void );
  416. static void cmd_focus_next_cpu( void );
  417. static void cmd_step( void );
  418. static void cmd_animate( void );
  419. static void cmd_step_over( void );
  420. static void cmd_go( void );
  421. static void cmd_search_memory( void );
  422.  
  423. /****************************************************************************
  424.  * Generic structure for saving points in the 'follow history'
  425.  ****************************************************************************/
  426. typedef struct {
  427.     UINT32  dasm_top;               /* previous top of window PC */
  428.     UINT32  dasm_cur;               /* previous cursor PC */
  429.     UINT32  mem1_base;              /* previous memory 1 base address */
  430.     UINT32  mem1_offset;            /* previous memory 1 offset */
  431.     UINT32  mem1_nibble;            /* previous memory 1 nibble */
  432. }   s_hist;
  433.  
  434. /****************************************************************************
  435.  * Symbol table entry
  436.  ****************************************************************************/
  437. typedef struct {
  438.     UINT32    value;                    /* value of the symbol */
  439.     INT32    access;                 /* access mode (EA_... enum) */
  440.     INT32    size;                    /* size of the element */
  441.     UINT32    times;                    /* repeat how many times */
  442.     char    name[47+1];             /* name of the symbol */
  443. }    s_symbol;
  444.  
  445. /****************************************************************************
  446.  * Generic structure for editing values
  447.  * x,y are the coordinates inside a window
  448.  * w is the width in hex digits (aka nibbles)
  449.  * n is the distance of the hex part from the start of the output (register)
  450.  ****************************************************************************/
  451. typedef struct {
  452.     UINT8    x,y,w,n;
  453. }    s_edit;
  454.  
  455. /****************************************************************************
  456.  * Register display and editing structure
  457.  ****************************************************************************/
  458. typedef struct {
  459.     UINT32  backup[MAX_REGS];       /* backup register values */
  460.     UINT32  newval[MAX_REGS];       /* new register values */
  461.     s_edit    edit[MAX_REGS];         /* list of x,y,w triplets for the register values */
  462.     char    name[MAX_REGS][15+1];    /* ...fifteen characters enough!? */
  463.     UINT8    id[MAX_REGS];            /* the ID of the register (cpu_get_reg/cpu_set_reg) */
  464.     UINT32    max_width;                /* maximum width of any dumped register */
  465.     INT32   idx;                    /* index of current register */
  466.     INT32   count;                  /* number of registers */
  467.     INT32   nibble;                 /* edit nibble */
  468.     INT32   changed;
  469.     INT32    top;
  470.     INT32    base;
  471. }    s_regs;
  472.  
  473. /****************************************************************************
  474.  * Memory display and editing structure
  475.  ****************************************************************************/
  476. typedef struct {
  477.     UINT8   backup[MAX_DATA];   /* backup data */
  478.     UINT8   newval[MAX_DATA];   /* newly read data */
  479.     s_edit    edit[MAX_DATA];     /* list of x,y,w triplets for the memory elements */
  480.     UINT32  base;               /* current base address */
  481.     UINT32    address;            /* current cursor address */
  482.     INT32   offset;             /* edit offset */
  483.     INT32   nibble;             /* edit nibble */
  484.     INT32    bytes;                /* number of bytes per edit line */
  485.     INT32    width;                /* width in nibbles of the edit line */
  486.     INT32    size;                /* number of bytes in the edit window */
  487.     UINT8    mode;                /* 0 bytes, 1 words, 2 dword */
  488.     UINT8    ascii;                /* display ASCII values */
  489.     UINT8   changed;
  490. }    s_mem;
  491.  
  492. /****************************************************************************
  493.  * Disassembly structure
  494.  ****************************************************************************/
  495. typedef struct {
  496.     UINT32    pc_cpu;             /* The CPUs PC */
  497.     UINT32    pc_top;             /* Top of the disassembly window PC */
  498.     UINT32    pc_cur;             /* Cursor PC */
  499.     UINT32    pc_end;             /* End of the disassembly window PC */
  500.     UINT32    dst_ea_value;        /* effective destination address or value */
  501.     INT32    dst_ea_access;        /* destination access mode */
  502.     INT32    dst_ea_size;        /* destination access size */
  503.     UINT32    src_ea_value;        /* effective source address or value */
  504.     INT32    src_ea_access;        /* source access mode */
  505.     INT32    src_ea_size;        /* source access size */
  506. }    s_dasm;
  507.  
  508. /****************************************************************************
  509.  * Tracing structure
  510.  ****************************************************************************/
  511. typedef struct {
  512.     UINT32  last_pc[MAX_LOOPS];
  513.     UINT8    regs[MAX_REGS];
  514.     FILE    *file;
  515.     INT32   iters;
  516.     INT32   loops;
  517. }    s_trace;
  518.  
  519. /****************************************************************************
  520.  * Debugger structure. There is one instance per CPU
  521.  ****************************************************************************/
  522. typedef struct {
  523.     UINT32    ignore;             /* ignore this CPU while debugging? */
  524.     UINT32    next_pc;
  525.     UINT32    prev_sp;
  526.  
  527.     /* Break- and Watchpoints */
  528.     UINT32    brk_exec;            /* execution breakpoint (program counter) */
  529.     UINT32    brk_exec_times;     /* how many times to ignore the breakpoint */
  530.     UINT32    brk_exec_reset;     /* reset value for times once it counted down */
  531.     UINT32    brk_data;            /* data watchpoint (memory address) */
  532.     UINT32    brk_data_oldval;    /* old data watchpoint value */
  533.     UINT32    brk_data_newval;    /* expected new value (INVALID: always break) */
  534.     UINT32    brk_regs;            /* register watchpoint (register ID) */
  535.     UINT32    brk_regs_oldval;    /* old register watchpoint value */
  536.     UINT32    brk_regs_newval;    /* expected new value (INVALID: always break) */
  537.     UINT32    brk_regs_mask;        /* mask register value before comparing */
  538.     UINT32    brk_temp;            /* temporary execution breakpoint */
  539.  
  540.     s_regs    regs;
  541.     s_dasm    dasm;
  542.     s_mem    mem[MAX_MEM];
  543.     s_trace trace;
  544.     INT32    hist_cnt;
  545.     s_hist    hist[MAX_HIST];
  546.  
  547.     char    cmdline[80+1];
  548.     UINT8    window;     /* edit what: cmds, regs, dasm, mem1, mem2 */
  549.  
  550. }    s_dbg;
  551.  
  552. static    s_dbg    dbg[MAX_CPU];
  553.  
  554. /* Covenience macros... keep the code readable */
  555. #define DBG     dbg[activecpu]
  556. #define DBGREGS dbg[activecpu].regs
  557. #define DBGDASM dbg[activecpu].dasm
  558. #define DBGMEM    dbg[activecpu].mem
  559. #define TRACE    dbg[tracecpu].trace
  560.  
  561. #define CMD     dbg[activecpu].cmdline
  562.  
  563. /****************************************************************************
  564.  * Tracing
  565.  ****************************************************************************/
  566. static int tracecpu = 0;
  567. static int trace_on = 0;
  568.  
  569. /****************************************************************************
  570.  * Commands structure
  571.  ****************************************************************************/
  572. typedef struct {
  573.     int valid;                /* command is valid for which windows (bit mask) */
  574.     const char *name;        /* command name (NULL none) */
  575.     const char *alias;        /* command name alias (NULL none) */
  576.     int key;                /* key code (0 none) */
  577.     const char *args;        /* description of expected arguments */
  578.     const char *info;        /* description of the function */
  579.     void (*function)(void); /* function handling the key/command */
  580. }    s_command;
  581.  
  582. #define ALL     ((1<<EDIT_CMDS)|(1<<EDIT_REGS)|(1<<EDIT_DASM)|(1<<EDIT_MEM1)|(1<<EDIT_MEM2))
  583.  
  584. static s_command commands[] = {
  585. {    (1<<EDIT_CMDS),
  586.     "A",            0,          CODE_NONE,
  587.     "[<update>]",
  588.     "Animate (trace) and update display every <update> opcodes only",
  589.     cmd_animate },
  590. {   (1<<EDIT_CMDS),
  591.     "D",            0,          CODE_NONE,
  592.     "<1|2> <address>",
  593.     "Display memory <1|2> starting at <address>",
  594.     cmd_display_memory },
  595. {   (1<<EDIT_CMDS),
  596.     "E",            0,          CODE_NONE,
  597.     "<1|2> [<address>]",
  598.     "Edit memory window <1|2> [at <address>]",
  599.     cmd_edit_memory },
  600. {    (1<<EDIT_CMDS),
  601.     "M",            0,          CODE_NONE,
  602.     "<1|2> [BYTE|WORD|DWORD]",
  603.     "Change memory window mode to default [to BYTE|WORD|DWORD (or 0|1|2)]",
  604.     cmd_set_memory_mode },
  605. {   (1<<EDIT_CMDS),
  606.     "F",            0,          CODE_NONE,
  607.     "",
  608.     "Fast",
  609.     cmd_fast },
  610. {   (1<<EDIT_CMDS),
  611.     "G",            0,          CODE_NONE,
  612.     "[<address>]",
  613.     "Go [and break at <address>]",
  614.     cmd_go_break },
  615. {   (1<<EDIT_CMDS),
  616.     "J",            0,          CODE_NONE,
  617.     "<address>",
  618.     "Jump to <address> in disassembly window",
  619.     cmd_jump },
  620. {   (1<<EDIT_CMDS),
  621.     "R",            0,          CODE_NONE,
  622.     "<register> <value>",
  623.     "Replace <register> with <value> (<value> may also be a <register>)",
  624.     cmd_replace_register },
  625. {   (1<<EDIT_CMDS),
  626.     "BP",           "BPX",      CODE_NONE,
  627.     "<address> [<times>]",
  628.     "Break on execution of <address> [after ignoring it <times>]",
  629.     cmd_brk_exec_set },
  630. {   (1<<EDIT_CMDS),
  631.     "BC",           0,          CODE_NONE,
  632.     "",
  633.     "Clear execution breakpoint",
  634.     cmd_brk_exec_clear },
  635. {    (1<<EDIT_CMDS),
  636.     "RP",           0,          CODE_NONE,
  637.     "<register> [<value> [<mask>]]",
  638.     "Break if <register> changes [to <value> [compare after applying <mask>]]",
  639.     cmd_brk_regs_set },
  640. {   (1<<EDIT_CMDS),
  641.     "RC",           0,          CODE_NONE,
  642.     "",
  643.     "Clear register watchpoint",
  644.     cmd_brk_regs_clear },
  645. {   (1<<EDIT_CMDS),
  646.     "WP",           "BPW",      CODE_NONE,
  647.     "<address> [<value>]",
  648.     "Break if data at <address> changes [to <value>]",
  649.     cmd_brk_data_set },
  650. {   (1<<EDIT_CMDS),
  651.     "WC",           0,          CODE_NONE,
  652.     "",
  653.     "Clear data watchpoint",
  654.     cmd_brk_data_clear },
  655. {    (1<<EDIT_CMDS),
  656.     "HERE",         0,          CODE_NONE,
  657.     "",
  658.     "Run to cursor",
  659.     cmd_here },
  660. {   (1<<EDIT_CMDS),
  661.     "DASM",         0,          CODE_NONE,
  662.     "<filename> <start> <end> [<boolean>]",
  663.     "Disassemble to <filename> from address <start> to <end>\n" \
  664.     "Opcode dump on by default [OFF|NO|0 without]",
  665.     cmd_dasm_to_file },
  666. {    (1<<EDIT_CMDS),
  667.     "DUMP",         0,          CODE_NONE,
  668.     "<filename> <start> <end> [<data size> [<ASCII mode>]]",
  669.     "Dump to <filename> from address <start> to <end>\n" \
  670.     "[data size BYTE|WORD|DWORD (also 0|1|2)]\n" \
  671.     "[ASCII mode OFF|TRANSLATE|FULL (also 0|1|2)]\n",
  672.     cmd_dump_to_file },
  673. {    (1<<EDIT_CMDS),
  674.     "TRACE",        0,          CODE_NONE,
  675.     "{<filename> [<reg1> [<reg2>...]]}|OFF",
  676.     "Trace to <filename> [dumping <reg1> [<reg2>...]] | OFF to stop tracing.",
  677.     cmd_trace_to_file },
  678. {    (1<<EDIT_CMDS),
  679.     "SAVE",         0,          CODE_NONE,
  680.     "<filename> <start> <end> [OPCODES|DATA]",
  681.     "Save binary to <filename> from address <start> to <end>\n" \
  682.     "[either OPCODES (from OP_ROM, default) or DATA (from OP_RAM), also 0|1].",
  683.     cmd_save_to_file },
  684. {   (1<<EDIT_CMDS),
  685.     "IGNORE",       0,          CODE_NONE,
  686.     "<cpunum>",
  687.     "Ignore CPU #<cpunum> while debugging or tracing",
  688.     cmd_set_ignore },
  689. {    (1<<EDIT_CMDS),
  690.     "OBSERVE",      0,          CODE_NONE,
  691.     "<cpunum>",
  692.     "Observe CPU #<cpunum> while debugging or tracing",
  693.     cmd_set_observe },
  694. {    (1<<EDIT_CMDS),
  695.     "CASE",         0,          CODE_NONE,
  696.     "DEFAULT|LOWER|UPPER (also 0|1|2)",
  697.     "Set disassembly case style.",
  698.     cmd_set_dasm_case },
  699. {   (1<<EDIT_CMDS),
  700.     "OPCODES",      0,          CODE_NONE,
  701.     "<boolean>",
  702.     "Display opcodes in disassembly window",
  703.     cmd_set_dasm_opcodes },
  704. {   (1<<EDIT_CMDS),
  705.     "RELATIVE",     0,          CODE_NONE,
  706.     "<boolean>",
  707.     "Display relative jump addresses in disassembly window",
  708.     cmd_set_dasm_relative_jumps },
  709. {    (1<<EDIT_CMDS),
  710.     "SQUEEZE",      0,        CODE_NONE,
  711.     "<boolean>",
  712.     "Allow squeezed memory display",
  713.     cmd_set_mem_squeezed },
  714. {    (1<<EDIT_CMDS),
  715.     "COLOR",       0,          CODE_NONE,
  716.     "<element> <foreground> [<background>]",
  717.     "Set <element> color to <foreground> on BLACK [or <background>].\nFor a list of <elements> and <colors> see mamedbg.cfg",
  718.     cmd_set_element_color },
  719. {   (1<<EDIT_CMDS),
  720.     "SCREEN",       0,          CODE_NONE,
  721.     "[<column> <lines>]",
  722.     "Set screen size to default [or to <columns> x <lines>]",
  723.     cmd_set_screen_size },
  724. {   (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  725.     0,                0,            KEYCODE_UP,
  726.     "",
  727.     "Move cursor up in disassembly window",
  728.     cmd_dasm_up },
  729. {    (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  730.     0,                0,            KEYCODE_DOWN,
  731.     "",
  732.     "Move cursor down in disassembly window",
  733.     cmd_dasm_down },
  734. {    (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  735.     0,                0,            KEYCODE_PGUP,
  736.     "",
  737.     "Move cursor up one page in disassembly window",
  738.     cmd_dasm_page_up },
  739. {    (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  740.     0,                0,            KEYCODE_PGDN,
  741.     "",
  742.     "Move cursor down one page in disassembly window",
  743.     cmd_dasm_page_down },
  744. {    (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  745.     0,                0,            KEYCODE_HOME,
  746.     "",
  747.     "Move cursor to first page in disassembly window",
  748.     cmd_dasm_home },
  749. {    (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  750.     0,                0,            KEYCODE_END,
  751.     "",
  752.     "Move cursor to last page in disassembly window",
  753.     cmd_dasm_end },
  754. {   (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  755.     0,                0,            KEYCODE_LEFT,
  756.     "",
  757.     "Back to the previous point in 'follow history'",
  758.     cmd_dasm_hist_back },
  759. {    (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  760.     0,                0,            KEYCODE_RIGHT,
  761.     "",
  762.     "Follow the current instruction's code or data reference",
  763.     cmd_dasm_hist_follow },
  764. {   ALL,
  765.     0,                0,            KEYCODE_TAB,
  766.     "",
  767.     "Switch between windows (backwards SHIFT+TAB)",
  768.     cmd_switch_window },
  769. {    (1<<EDIT_DASM),
  770.     0,              0,          KEYCODE_D,
  771.     "",
  772.     "Change disassembly case style to default",
  773.     NULL },
  774. {    (1<<EDIT_DASM),
  775.     0,                0,            KEYCODE_L,
  776.     "",
  777.     "Change disassembly case style to lower case",
  778.     NULL },
  779. {    (1<<EDIT_DASM),
  780.     0,                0,            KEYCODE_U,
  781.     "",
  782.     "Change disassembly case style to upper case",
  783.     NULL },
  784. {    (1<<EDIT_DASM),
  785.     0,                0,            KEYCODE_M,
  786.     "",
  787.     "Toggle disassembly opcode display mode",
  788.     NULL },
  789. {    (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
  790.     0,                0,            KEYCODE_H,
  791.     "",
  792.     "Toggle between hex, ASCII and full character set mode",
  793.     NULL },
  794. {   (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
  795.     0,                0,            KEYCODE_M,
  796.     "",
  797.     "Switch memory display mode between bytes, words and dwords",
  798.     NULL },
  799. {    (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
  800.     0,                0,            KEYCODE_S,
  801.     "",
  802.     "Search memory for a sequence of bytes",
  803.     cmd_search_memory },
  804. {   ALL,
  805.     0,                0,            KEYCODE_F1,
  806.     "",
  807.     "Help - maybe you realized this ;)",
  808.     cmd_help },
  809. {    (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  810.     0,                0,            KEYCODE_F2,
  811.     "",
  812.     "Toggle breakpoint at current cursor position",
  813.     cmd_brk_exec_toggle },
  814. {    (1<<EDIT_CMDS)|(1<<EDIT_DASM),
  815.     0,                0,            KEYCODE_F4,
  816.     "",
  817.     "Run to cursor",
  818.     cmd_run_to_cursor },
  819. {    (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
  820.     0,                0,            KEYCODE_F4,
  821.     "",
  822.     "Set data watchpoint to current memory location",
  823.     cmd_brk_data_toggle },
  824. {   ALL,
  825.     0,                0,            KEYCODE_F5,
  826.     "",
  827.     "View emulation screen",
  828.     cmd_view_screen },
  829. {    ALL,
  830.     0,                0,            KEYCODE_F6,
  831.     "",
  832.     "Set the focus to the next (not ignored) CPU",
  833.     cmd_focus_next_cpu },
  834. {    ALL,
  835.     0,                0,            KEYCODE_F8,
  836.     "",
  837.     "Step one instruction",
  838.     cmd_step },
  839. {    ALL,
  840.     0,                0,            KEYCODE_F9,
  841.     "",
  842.     "Animate (trace) at speed set by last \"A\" command",
  843.     cmd_animate },
  844. {    ALL,
  845.     0,                0,            KEYCODE_F10,
  846.     "",
  847.     "Step over instruction at cursor (ie. execute call, jsr or bsr)",
  848.     cmd_step_over },
  849. {    ALL,
  850.     0,                0,            KEYCODE_F12,
  851.     "",
  852.     "Go!",
  853.     cmd_go },
  854. {    ALL,
  855.     0,                0,            KEYCODE_ESC,
  856.     "",
  857.     "Go!",
  858.     cmd_go },
  859. /* This is the end of the list! */
  860. { 0,    },
  861. };
  862.  
  863. INLINE unsigned order( unsigned offset, unsigned size )
  864. {
  865.     switch( size )
  866.     {
  867.     case 1:
  868.         return offset;
  869.         break;
  870.     case 2:
  871.         switch( ENDIAN )
  872.         {
  873.         case CPU_IS_LE: return UINT16_XOR_LE(offset);
  874.         case CPU_IS_BE: return UINT16_XOR_BE(offset);
  875.         }
  876.         break;
  877.     case 4:
  878.         switch( ENDIAN )
  879.         {
  880.         case CPU_IS_LE: return UINT32_XOR_LE(offset);
  881.         case CPU_IS_BE: return UINT32_XOR_BE(offset);
  882.         }
  883.         break;
  884.     }
  885.     return offset;
  886. }
  887.  
  888. /* adjust an offset by shifting it left cpu_address_shift() times */
  889. INLINE unsigned lshift( unsigned offset )
  890. {
  891.     switch( ASHIFT )
  892.     {
  893.         case -1: return offset / 2;
  894.         case  3: return offset * 8;
  895.     }
  896.     return offset;
  897. }
  898.  
  899. /* adjust an offset by shifting it right cpu_address_shift() times */
  900. INLINE unsigned rshift( unsigned offset )
  901. {
  902.     switch( ASHIFT )
  903.     {
  904.         case -1: return offset * 2;
  905.         case  3: return offset / 8;
  906.     }
  907.     return offset;
  908. }
  909.  
  910.  
  911. /**************************************************************************
  912.  * dtou
  913.  * Decimal to unsigned.
  914.  * The pointer to the char* is placed after all consecutive digits
  915.  * and trailing space. The pointer to int size (if given) contains the
  916.  * number of digits found.
  917.  **************************************************************************/
  918. INLINE unsigned dtou( char **parg, int *size)
  919. {
  920.     unsigned val = 0, digit;
  921.  
  922.     if (size) *size = 0;
  923.     while( isdigit( *(*parg) ) )
  924.     {
  925.         digit = *(*parg) - '0';
  926.         val = (val * 10) + digit;
  927.         if( size ) (*size)++;
  928.         (*parg) += 1;
  929.     }
  930.     while( isspace(*(*parg)) ) *parg += 1;
  931.     return val;
  932. }
  933.  
  934. /**************************************************************************
  935.  * xtou
  936.  * Hex to unsigned.
  937.  * The pointer to the char* is placed after all consecutive hex digits
  938.  * and trailing space. The pointer to int size (if given) contains the
  939.  * number of digits found.
  940.  **************************************************************************/
  941. INLINE unsigned xtou( char **parg, int *size)
  942. {
  943.     unsigned val = 0, digit;
  944.  
  945.     if (size) *size = 0;
  946.     while( isxdigit( *(*parg) ) )
  947.     {
  948.         digit = toupper(*(*parg)) - '0';
  949.         if( digit > 9 ) digit -= 7;
  950.         val = (val << 4) | digit;
  951.         if( size ) (*size)++;
  952.         (*parg) += 1;
  953.     }
  954.     while( isspace(*(*parg)) ) *parg += 1;
  955.     return val;
  956. }
  957.  
  958. const char *set_ea_info( int what, unsigned value, int size, int access )
  959. {
  960.     static char buffer[8][63+1];
  961.     static int which = 0;
  962.     const char *sign = "";
  963.     unsigned width, result;
  964.  
  965.     which = ++which % 8;
  966.  
  967.     if( access == EA_REL_PC )
  968.         /* PC relative calls set_ea_info with value = PC and size = offset */
  969.         result = value + size;
  970.     else
  971.         result = value;
  972.  
  973.     /* set source EA? */
  974.     if( what == EA_SRC )
  975.     {
  976.         DBGDASM.src_ea_access = access;
  977.         DBGDASM.src_ea_value = result;
  978.         DBGDASM.src_ea_size = size;
  979.     }
  980.     else
  981.     if( what == EA_DST )
  982.     {
  983.         DBGDASM.dst_ea_access = access;
  984.         DBGDASM.dst_ea_value = result;
  985.         DBGDASM.dst_ea_size = size;
  986.     }
  987.     else
  988.     {
  989.         return "set_ea_info: invalid <what>!";
  990.     }
  991.  
  992.     switch( access )
  993.     {
  994.     case EA_VALUE:    /* Immediate value */
  995.         switch( size )
  996.         {
  997.         case EA_INT8:
  998.             width = 2;
  999.             result &= 0xff;
  1000.             if( result & 0x80 )
  1001.             {
  1002.                 sign = "-";
  1003.                 result = (unsigned)-result;
  1004.             }
  1005.             break;
  1006.         case EA_INT16:
  1007.             width = 4;
  1008.             result &= 0xffff;
  1009.             if( result & 0x8000 )
  1010.             {
  1011.                 sign = "-";
  1012.                 result = (unsigned)-result;
  1013.             }
  1014.             break;
  1015.         case EA_INT32:
  1016.             width = 8;
  1017.             if( result & 0x80000000 )
  1018.             {
  1019.                 sign = "-";
  1020.                 result = (unsigned)-result;
  1021.             }
  1022.             break;
  1023.         case EA_UINT8:
  1024.             width = 2;
  1025.             result &= 0xff;
  1026.             break;
  1027.         case EA_UINT16:
  1028.             width = 4;
  1029.             result &= 0xffff;
  1030.             break;
  1031.         case EA_UINT32:
  1032.             width = 8;
  1033.             break;
  1034.         default:
  1035.             return "set_ea_info: invalid <size>!";
  1036.         }
  1037.         break;
  1038.  
  1039.     case EA_ZPG_RD:
  1040.     case EA_ZPG_WR:
  1041.     case EA_ZPG_RDWR:
  1042.         result &= 0xff;
  1043.         width = 2;
  1044.         break;
  1045.  
  1046.     case EA_ABS_PC: /* Absolute program counter change */
  1047.         result &= AMASK;
  1048.         if( size == EA_INT8 || size == EA_UINT8 )
  1049.             width = 2;
  1050.         else
  1051.         if( size == EA_INT16 || size == EA_UINT16 )
  1052.             width = 4;
  1053.         else
  1054.         if( size == EA_INT32 || size == EA_UINT32 )
  1055.             width = 8;
  1056.         else
  1057.             width = (ABITS + 3) / 4;
  1058.         break;
  1059.  
  1060.     case EA_REL_PC: /* Relative program counter change */
  1061.         if( dbg_dasm_relative_jumps )
  1062.         {
  1063.             if( size == 0 )
  1064.                 return "$";
  1065.             if( size < 0 )
  1066.             {
  1067.                 sign = "-";
  1068.                 result = (unsigned) -size;
  1069.             }
  1070.             else
  1071.             {
  1072.                 sign = "+";
  1073.                 result = (unsigned) size;
  1074.             }
  1075.             sprintf( buffer[which], "$%s%u", sign, result );
  1076.             return buffer[which];
  1077.         }
  1078.         /* fall through */
  1079.     default:
  1080.         result &= AMASK;
  1081.         width = (ABITS + 3) / 4;
  1082.     }
  1083.     sprintf( buffer[which], "%s$%0*X", sign, width, result );
  1084.     return buffer[which];
  1085. }
  1086.  
  1087. /**************************************************************************
  1088.  * lower
  1089.  * Convert string into all lower case.
  1090.  **************************************************************************/
  1091. INLINE char *lower( const char *src)
  1092. {
  1093.     static char buffer[127+1];
  1094.     char *dst = buffer;
  1095.     while( *src )
  1096.         *dst++ = tolower(*src++);
  1097.     *dst = '\0';
  1098.     return buffer;
  1099. }
  1100.  
  1101. /**************************************************************************
  1102.  * upper
  1103.  * Convert string into all upper case.
  1104.  **************************************************************************/
  1105. INLINE char *upper( const char *src)
  1106. {
  1107.     static char buffer[127+1];
  1108.     char *dst = buffer;
  1109.     while( *src )
  1110.         *dst++ = toupper(*src++);
  1111.     *dst = '\0';
  1112.     return buffer;
  1113. }
  1114.  
  1115. /**************************************************************************
  1116.  * kilobyte
  1117.  * Format a byte count or size to a kilo or mega bytes string
  1118.  **************************************************************************/
  1119. INLINE char *kilobyte( unsigned bytes )
  1120. {
  1121.     static char buffer[2][31+1];
  1122.     static int which = 0;
  1123.     char *dst = buffer[which];
  1124.     which ^= 1;
  1125.     if( bytes < 1024 )
  1126.         sprintf( dst, "%u", bytes );
  1127.     else
  1128.     if( bytes < 1024 * 1024 )
  1129.         sprintf( dst, "%u.%02uK", bytes / 1024, 100 * bytes / 1024 );
  1130.     else
  1131.         sprintf( dst, "%u.%02uM", bytes / 1024 / 1024, 100 * ((bytes / 1024) % 1024) / 1024 );
  1132.     return dst;
  1133. }
  1134.  
  1135. /**************************************************************************
  1136.  * my_stricmp
  1137.  * Compare strings case insensitive
  1138.  **************************************************************************/
  1139. INLINE int my_stricmp( const char *dst, const char *src)
  1140. {
  1141.     while( *src && *dst )
  1142.     {
  1143.         if( tolower(*src) != tolower(*dst) ) return *dst - *src;
  1144.         src++;
  1145.         dst++;
  1146.     }
  1147.     return *dst - *src;
  1148. }
  1149.  
  1150. /**************************************************************************
  1151.  * get_boolean
  1152.  * Get a boolean argument (on/off, yes/no, y/n, 1/0)
  1153.  **************************************************************************/
  1154. static unsigned get_boolean( char **parg, int *size )
  1155. {
  1156.     char *p = *parg;
  1157.     unsigned result = 0;
  1158.     int length = 0;
  1159.  
  1160.     if( toupper(p[0]) == 'O' )
  1161.     {
  1162.         if( toupper(p[1]) == 'N' && !isalnum(p[2]) )
  1163.         {
  1164.             result = 1;
  1165.             length = 2;
  1166.             *parg += length;
  1167.         }
  1168.         else
  1169.         if( toupper(p[1]) == 'F' && toupper(p[2]) == 'F' && !isalnum(p[3]) )
  1170.         {
  1171.             result = 0;
  1172.             length = 3;
  1173.             *parg += length;
  1174.         }
  1175.     }
  1176.     else
  1177.     if( toupper(p[0]) == 'N' )
  1178.     {
  1179.         if( toupper(p[1]) == 'O' && !isalnum(p[2]) )
  1180.         {
  1181.             result = 0;
  1182.             length = 2;
  1183.             *parg += length;
  1184.         }
  1185.         else
  1186.         if( !isalnum(p[1]) )
  1187.         {
  1188.             result = 0;
  1189.             length = 1;
  1190.             *parg += length;
  1191.         }
  1192.     }
  1193.     else
  1194.     if( toupper(p[0]) == 'Y' )
  1195.     {
  1196.         if( toupper(p[1]) == 'E' && toupper(p[2]) == 'S' && !isalnum(p[3]) )
  1197.         {
  1198.             result = 1;
  1199.             length = 3;
  1200.             *parg += length;
  1201.         }
  1202.         else
  1203.         if( !isalnum(p[1]) )
  1204.         {
  1205.             result = 0;
  1206.             length = 1;
  1207.             *parg += length;
  1208.         }
  1209.     }
  1210.  
  1211.     if( length )
  1212.     {
  1213.         while( isspace(*(*parg)) ) *parg += 1;
  1214.     }
  1215.     else
  1216.     {
  1217.         /* found nothing yet: assume numeric */
  1218.         result = xtou( parg, &length );
  1219.     }
  1220.  
  1221.     if( size ) *size += length;
  1222.  
  1223.     return result;
  1224. }
  1225.  
  1226. /**************************************************************************
  1227.  * get_option_or_value
  1228.  * Get a option argument (from opt_list) or a number in the
  1229.  * range of 0 .. number of options - 1
  1230.  **************************************************************************/
  1231. static unsigned get_option_or_value( char **parg, int *size, const char *opt_list )
  1232. {
  1233.     char *p = *parg;
  1234.     const char *opt;
  1235.     unsigned result = 0, opt_count = 0;
  1236.     int length = 0;
  1237.  
  1238.     /* length of the next argument */
  1239.     while( isalnum(*p) ) p++;
  1240.     length = (int) (p - *parg);
  1241.     while( isspace(*p) ) p++;
  1242.  
  1243.     /* sacn options */
  1244.     for( opt = opt_list; *opt ; opt += strlen(opt) + 1 )
  1245.     {
  1246.         if( strncmp(*parg, opt, length) == 0 )
  1247.         {
  1248.             *parg = p;
  1249.             if( size ) *size = length;
  1250.             return opt_count;
  1251.         }
  1252.         opt_count++;
  1253.     }
  1254.  
  1255.     result = xtou( parg, &length );
  1256.     if( size ) *size += length;
  1257.  
  1258.     return result;
  1259. }
  1260.  
  1261. static const char *get_file_name( char **parg, int *size )
  1262. {
  1263.     static char filename[127+1];
  1264.     char *s, *d;
  1265.     int l;
  1266.  
  1267.     for( l = 0, s = *parg, d = filename; *s && (isalnum(*s) || ispunct(*s)); l++ )
  1268.         *d++ = *s++;
  1269.  
  1270.     *d = '\0';
  1271.     while( isspace(*s) ) s++;
  1272.     *parg = s;
  1273.  
  1274.     if( size ) *size = l;
  1275.  
  1276.     return filename;
  1277. }
  1278.  
  1279. const char *get_ea_info( unsigned pc )
  1280. {
  1281.     static char buffer[63+1];
  1282.     static char *access[EA_COUNT] =
  1283.     {
  1284.         "",     /* no EA mode */
  1285.         "#",    /* immediate */
  1286.         "=",    /* absolute PC */
  1287.         "$",    /* relative PC */
  1288.         "<",    /* zero page memory read */
  1289.         ">",    /* zero page memory write */
  1290.         "*",    /* zero page memory modify */
  1291.         "<",    /* memory read */
  1292.         ">",    /* memory write */
  1293.         "*",    /* memory modify */
  1294.         "P<",   /* port read */
  1295.         "P>"    /* port write */
  1296.     };
  1297.  
  1298.     unsigned wdst, wsrc;
  1299.  
  1300.     switch( DBGDASM.dst_ea_size )
  1301.     {
  1302.         case EA_INT8:    wdst = 2; break;
  1303.         case EA_INT16:    wdst = 4; break;
  1304.         case EA_INT32:    wdst = 8; break;
  1305.         case EA_UINT8:    wdst = 2; break;
  1306.         case EA_UINT16: wdst = 4; break;
  1307.         case EA_UINT32: wdst = 8; break;
  1308.         default:
  1309.             wdst = (ABITS + 3) / 4;
  1310.     }
  1311.  
  1312.     switch( DBGDASM.src_ea_size )
  1313.     {
  1314.         case EA_INT8:    wsrc = 2; break;
  1315.         case EA_INT16:    wsrc = 4; break;
  1316.         case EA_INT32:    wsrc = 8; break;
  1317.         case EA_UINT8:    wsrc = 2; break;
  1318.         case EA_UINT16: wsrc = 4; break;
  1319.         case EA_UINT32: wsrc = 8; break;
  1320.         default:
  1321.             wsrc = (ABITS + 3) / 4;
  1322.     }
  1323.  
  1324.     if( DBGDASM.dst_ea_value != INVALID && DBGDASM.src_ea_value != INVALID )
  1325.         sprintf( buffer, "%s\t%s%0*X %s%0*X",
  1326.             name_rdmem(rshift(pc)),
  1327.             access[DBGDASM.src_ea_access], wsrc, DBGDASM.src_ea_value,
  1328.             access[DBGDASM.dst_ea_access], wdst, DBGDASM.dst_ea_value );
  1329.     else
  1330.     if( DBGDASM.dst_ea_value != INVALID )
  1331.         sprintf( buffer, "%s\t%s%0*X",
  1332.             name_rdmem(rshift(pc)),
  1333.             access[DBGDASM.dst_ea_access], wdst, DBGDASM.dst_ea_value );
  1334.     else
  1335.     if( DBGDASM.src_ea_value != INVALID )
  1336.         sprintf( buffer, "%s\t%s%0*X",
  1337.             name_rdmem(rshift(pc)),
  1338.             access[DBGDASM.src_ea_access], wsrc, DBGDASM.src_ea_value );
  1339.     else
  1340.         sprintf( buffer, "%s", name_rdmem(rshift(pc)) );
  1341.  
  1342.     return buffer;
  1343. }
  1344.  
  1345. /**************************************************************************
  1346.  * get_register_id
  1347.  * Return the ID for a register if the string at *parg matches one
  1348.  * of the register names for the active cpu.
  1349.  **************************************************************************/
  1350. static unsigned get_register_id( char **parg, int *size )
  1351. {
  1352.     int i, l;
  1353.     for( i = 0; i < DBGREGS.count; i++ )
  1354.     {
  1355.         l = strlen( DBGREGS.name[i] );
  1356.         if( l > 0 && !strncmp( *parg, DBGREGS.name[i], l ) )
  1357.         {
  1358.             if( !isalnum( (*parg)[l] ) )
  1359.             {
  1360.                 if( size ) *size = l;
  1361.                 *parg += l;
  1362.                 while( isspace(*(*parg)) ) *parg += 1;
  1363.                 return DBGREGS.id[i];
  1364.             }
  1365.         }
  1366.     }
  1367.     if( size ) *size = 0;
  1368.     return 0;
  1369. }
  1370.  
  1371. /**************************************************************************
  1372.  * get_register_name
  1373.  * Get the name of a register with ID
  1374.  **************************************************************************/
  1375. static const char *get_register_name( int id )
  1376. {
  1377.     int i;
  1378.     for( i = 0; i < DBGREGS.count; i++ )
  1379.     {
  1380.         if( DBGREGS.id[i] == id )
  1381.             return DBGREGS.name[i];
  1382.     }
  1383.     return "??";
  1384. }
  1385.  
  1386. /**************************************************************************
  1387.  * get_register_or_value
  1388.  * Return the value for a register if the string at *parg matches one
  1389.  * of the register names for the active cpu. Otherwise get a hex
  1390.  * value from *parg. In both cases set the pointer int size to the
  1391.  * length of the name or digits found (if size is not NULL)
  1392.  **************************************************************************/
  1393. static unsigned get_register_or_value( char **parg, int *size )
  1394. {
  1395.     int regnum, l;
  1396.  
  1397.     regnum = get_register_id( parg, &l );
  1398.     if( regnum > 0 )
  1399.     {
  1400.         if( size ) *size = l;
  1401.         return cpu_get_reg( regnum );
  1402.     }
  1403.     /* default to hex value */
  1404.     return xtou( parg, size );
  1405. }
  1406.  
  1407. /**************************************************************************
  1408.  * trace_init
  1409.  * Creates trace output files for all CPUs
  1410.  * Resets the loop and iteration counters and the last PC array
  1411.  **************************************************************************/
  1412. static void trace_init( const char *filename, UINT8 *regs )
  1413. {
  1414.     char name[100];
  1415.  
  1416.     if( trace_on )
  1417.         return;
  1418.  
  1419.     for( tracecpu = 0; tracecpu < totalcpu; tracecpu++ )
  1420.     {
  1421.         sprintf( name, "%s.%d", filename, tracecpu );
  1422.         TRACE.file = fopen(name,"w");
  1423.         if( tracecpu == activecpu )
  1424.             memcpy( TRACE.regs, regs, MAX_REGS );
  1425.         else
  1426.             TRACE.regs[0] = 0;
  1427.         TRACE.iters = 0;
  1428.         TRACE.loops = 0;
  1429.         memset(TRACE.last_pc, 0xff, sizeof(TRACE.last_pc));
  1430.     }
  1431.     tracecpu = activecpu;
  1432.     trace_on = 1;
  1433. }
  1434.  
  1435. /**************************************************************************
  1436.  * trace_done
  1437.  * Closes the trace output files
  1438.  **************************************************************************/
  1439. void trace_done(void)
  1440. {
  1441.     if( !trace_on )
  1442.         return;
  1443.  
  1444.     for( tracecpu = 0; tracecpu < totalcpu; tracecpu++ )
  1445.     {
  1446.         if( TRACE.file )
  1447.             fclose( TRACE.file );
  1448.         TRACE.file = NULL;
  1449.     }
  1450.  
  1451.     trace_on = 0;
  1452. }
  1453.  
  1454. /**************************************************************************
  1455.  * trace_select
  1456.  * Switches tracing to the active CPU
  1457.  **************************************************************************/
  1458. static void trace_select( void )
  1459. {
  1460.     if( tracecpu == activecpu )
  1461.         return;
  1462.     if( trace_on && TRACE.file )
  1463.     {
  1464.         if( TRACE.loops )
  1465.         {
  1466.             fprintf( TRACE.file,
  1467.                 "\n   (loops for %d instructions)\n\n",
  1468.                 TRACE.loops );
  1469.             TRACE.loops = 0;
  1470.         }
  1471.         fprintf(TRACE.file,"\n=============== End of iteration #%d ===============\n\n",TRACE.iters++);
  1472.         fflush(TRACE.file);
  1473.     }
  1474.     if( activecpu < totalcpu )
  1475.         tracecpu = activecpu;
  1476. }
  1477.  
  1478. /**************************************************************************
  1479.  * trace_output
  1480.  * Outputs the next disassembled instruction to the trace file
  1481.  * Loops are detected and a loop count is output after the
  1482.  * first repetition instead of disassembling the loop over and over
  1483.  **************************************************************************/
  1484. static void trace_output( void )
  1485. {
  1486.     static char buffer[127+1];
  1487.     char *dst = buffer;
  1488.  
  1489.     if( trace_on && TRACE.file )
  1490.     {
  1491.         unsigned pc = cpu_get_pc();
  1492.         unsigned addr_width = (ABITS + 3) / 4;
  1493.         int count, i;
  1494.  
  1495.         // check for trace_loops
  1496.         for( i = count = 0; i < MAX_LOOPS; i++ )
  1497.             if( TRACE.last_pc[i] == pc )
  1498.                 count++;
  1499.         if( count > 1 )
  1500.         {
  1501.             TRACE.loops++;
  1502.         }
  1503.         else
  1504.         {
  1505.             if( TRACE.loops )
  1506.             {
  1507.                 dst += sprintf( dst,
  1508.                     "\n   (loops for %d instructions)\n\n",
  1509.                     TRACE.loops );
  1510.                 TRACE.loops = 0;
  1511.             }
  1512.             if( TRACE.regs[0] )
  1513.             {
  1514.                 for( i = 0; i < MAX_REGS && TRACE.regs[i]; i++ )
  1515.                     dst += sprintf( dst, "%s ", cpu_dump_reg(TRACE.regs[i]) );
  1516.             }
  1517.             dst += sprintf( dst, "%0*X: ", addr_width, pc );
  1518.             cpu_dasm( dst, pc );
  1519.             strcat( dst, "\n" );
  1520.             fprintf( TRACE.file, "%s", buffer );
  1521.             memmove(
  1522.                 &TRACE.last_pc[0],
  1523.                 &TRACE.last_pc[1],
  1524.                 (MAX_LOOPS-1)*sizeof(TRACE.last_pc[0]) );
  1525.             TRACE.last_pc[MAX_LOOPS-1] = pc;
  1526.         }
  1527.     }
  1528. }
  1529.  
  1530. /**************************************************************************
  1531.  * hit_brk_exec
  1532.  * Return non zero if execution breakpoint for the activecpu,
  1533.  * the temporary breakpoint or the break on 'activecpu' was hit
  1534.  **************************************************************************/
  1535. static int hit_brk_exec(void)
  1536. {
  1537.     static char dbg_info[63+1];
  1538.     UINT32 pc = cpu_get_pc();
  1539.  
  1540.     if( DBG.brk_temp != INVALID && DBG.brk_temp == pc )
  1541.     {
  1542.         sprintf( dbg_info, "Hit temp breakpoint at $%X", DBG.brk_temp);
  1543.         dbg_info_once = dbg_info;
  1544.         return 1;
  1545.     }
  1546.     if( DBG.brk_exec != INVALID && DBG.brk_exec == pc )
  1547.     {
  1548.         if( DBG.brk_exec_times > 0 )
  1549.         {
  1550.             if( --DBG.brk_exec_times == 0 )
  1551.             {
  1552.                 sprintf( dbg_info, "Hit exec breakpoint %d times", DBG.brk_exec_reset);
  1553.                 dbg_info_once = dbg_info;
  1554.                 return 1;
  1555.             }
  1556.             return 0;
  1557.         }
  1558.         sprintf( dbg_info, "Hit exec breakpoint at $%X", DBG.brk_exec);
  1559.         dbg_info_once = dbg_info;
  1560.         return 1;
  1561.     }
  1562.  
  1563.     return 0;
  1564. }
  1565.  
  1566. /**************************************************************************
  1567.  * hit_brk_data
  1568.  * Return non zero if the data watchpoint for the activecpu
  1569.  * was hit (ie. monitored data changed)
  1570.  **************************************************************************/
  1571. static int hit_brk_data(void)
  1572. {
  1573.     static char dbg_info[63+1];
  1574.     UINT32 data;
  1575.  
  1576.     if( DBG.brk_data == INVALID ) return 0;
  1577.  
  1578.     data = RDMEM(DBG.brk_data);
  1579.  
  1580.     if( DBG.brk_data_oldval != data )
  1581.     {
  1582.         DBG.brk_data_oldval = data;
  1583.         if( DBG.brk_data_newval != INVALID )
  1584.         {
  1585.             if( DBG.brk_data_newval == data )
  1586.             {
  1587.                 sprintf( dbg_info, "Hit data watchpoint at $%X value $%X", DBG.brk_data, DBG.brk_data_newval);
  1588.                 dbg_info_once = dbg_info;
  1589.                 return 1;
  1590.             }
  1591.             return 0;
  1592.         }
  1593.         sprintf( dbg_info, "Hit data watchpoint at $%X", DBG.brk_data);
  1594.         dbg_info_once = dbg_info;
  1595.         return 1;
  1596.     }
  1597.     return 0;
  1598. }
  1599.  
  1600.  
  1601. /**************************************************************************
  1602.  * hit_brk_regs
  1603.  * Return non zero if the register breakpoint for the active CPU
  1604.  * was hit (ie. monitored register changed)
  1605.  **************************************************************************/
  1606. static int hit_brk_regs(void)
  1607. {
  1608.     static char dbg_info[63+1];
  1609.     UINT32 data;
  1610.  
  1611.     if( DBG.brk_regs == INVALID ) return 0;
  1612.  
  1613.     data = cpu_get_reg(DBG.brk_regs);
  1614.  
  1615.     if( DBG.brk_regs_oldval != data )
  1616.     {
  1617.         DBG.brk_regs_oldval = data;
  1618.         if( DBG.brk_regs_newval != INVALID )
  1619.         {
  1620.             if( DBG.brk_regs_newval == (data & DBG.brk_regs_mask) )
  1621.             {
  1622.                 if( DBG.brk_regs_mask != 0xffffffff )
  1623.                     sprintf( dbg_info, "Hit register %s & $%X watchpoint value $%X", get_register_name(DBG.brk_regs), DBG.brk_regs_mask, DBG.brk_regs_newval);
  1624.                 else
  1625.                     sprintf( dbg_info, "Hit register %s watchpoint value $%X", get_register_name(DBG.brk_regs), DBG.brk_regs_newval);
  1626.                 dbg_info_once = dbg_info;
  1627.                 return 1;
  1628.             }
  1629.             return 0;
  1630.         }
  1631.         sprintf( dbg_info, "Hit register %s watchpoint", get_register_name(DBG.brk_regs));
  1632.         dbg_info_once = dbg_info;
  1633.         return 1;
  1634.     }
  1635.     return 0;
  1636. }
  1637.  
  1638.  
  1639. /**************************************************************************
  1640.  * name_rom
  1641.  * Find the name for a rom from the drivers list
  1642.  **************************************************************************/
  1643. static const char *name_rom( const char *type, int region, unsigned *base, unsigned start )
  1644. {
  1645.     const struct RomModule *romp = Machine->gamedrv->rom;
  1646.     unsigned offset = *base;
  1647.  
  1648.     while( romp && (romp->name || romp->offset || romp->length ) )
  1649.     {
  1650.         romp++; /* skip memory region definition */
  1651.  
  1652.         while( romp->length )
  1653.         {
  1654.             const char *name;
  1655.             int length;
  1656.  
  1657.             name = romp->name;
  1658.             length = 0;
  1659.  
  1660.             do
  1661.             {
  1662.                 /* ROM_RELOAD */
  1663.                 if (romp->name == (char *)-1)
  1664.                     length = 0; /* restart */
  1665.  
  1666.                 length += romp->length & ~ROMFLAG_MASK;
  1667.  
  1668.                 romp++;
  1669.  
  1670.             } while (romp->length && (romp->name == 0 || romp->name == (char *)-1));
  1671.  
  1672.             /* region found already ? */
  1673.             if( region == 0 )
  1674.             {
  1675.                 /* address inside that range ? */
  1676.                 if( offset < length )
  1677.                 {
  1678.                     /* put back that offset */
  1679.                     *base = offset;
  1680.                     return name;
  1681.                 }
  1682.                 /* subtract length of that ROM */
  1683.                 offset -= length;
  1684.             }
  1685.  
  1686.         }
  1687.         --region;
  1688.     }
  1689.  
  1690.     /* default to ROM + xxxx (base - start) */
  1691.     *base -= start;
  1692.     return type;
  1693. }
  1694.  
  1695. /**************************************************************************
  1696.  * name_rdmem
  1697.  * Find a descriptive name for the given memory read region of activecpu
  1698.  **************************************************************************/
  1699. static const char *name_rdmem( unsigned base )
  1700. {
  1701.     static char buffer[16][79+1];
  1702.     static int which = 0;
  1703.     const struct MachineCPU *cpu = &Machine->drv->cpu[activecpu];
  1704.     const struct MemoryReadAddress *mr = cpu->memory_read;
  1705.     int ram_cnt = 1, nop_cnt = 1;
  1706.     const char *name;
  1707.     char *dst;
  1708.  
  1709.     which = ++which % 16;
  1710.     dst = buffer[which];
  1711.     *dst = '\0';
  1712.  
  1713.     while( *dst == '\0' && mr->start != -1 )
  1714.     {
  1715.         if( base >= mr->start && base <= mr->end )
  1716.         {
  1717.             unsigned offset = base - mr->start;
  1718.  
  1719. //            if( mr->description )
  1720. //                sprintf(dst, "%s+%04X", mr->description, lshift(offset) );
  1721. //            else
  1722. //            if( mr->base && *mr->base == videoram )
  1723. //                sprintf(dst, "video+%04X", lshift(offset) );
  1724. //            else
  1725. //            if( mr->base && *mr->base == colorram )
  1726. //                sprintf(dst, "color+%04X", lshift(offset) );
  1727. //            else
  1728. //            if( mr->base && *mr->base == spriteram )
  1729. //                sprintf(dst, "sprite+%04X", lshift(offset) );
  1730. //            else
  1731.             switch( (FPTR)mr->handler )
  1732.             {
  1733.             case (FPTR)MRA_RAM:
  1734.                 sprintf(dst, "RAM%d+%04X", ram_cnt, lshift(offset) );
  1735.                 break;
  1736.             case (FPTR)MRA_ROM:
  1737.                 name = name_rom("ROM", REGION_CPU1+activecpu, &base, mr->start );
  1738.                 sprintf(dst, "%s+%04X", name, lshift(base) );
  1739.                 break;
  1740.             case (FPTR)MRA_BANK1:
  1741.                 sprintf(dst, "BANK1+%04X", lshift(offset) );
  1742.                 break;
  1743.             case (FPTR)MRA_BANK2:
  1744.                 sprintf(dst, "BANK2+%04X", lshift(offset) );
  1745.                 break;
  1746.             case (FPTR)MRA_BANK3:
  1747.                 sprintf(dst, "BANK3+%04X", lshift(offset) );
  1748.                 break;
  1749.             case (FPTR)MRA_BANK4:
  1750.                 sprintf(dst, "BANK4+%04X", lshift(offset) );
  1751.                 break;
  1752.             case (FPTR)MRA_BANK5:
  1753.                 sprintf(dst, "BANK5+%04X", lshift(offset) );
  1754.                 break;
  1755.             case (FPTR)MRA_BANK6:
  1756.                 sprintf(dst, "BANK6+%04X", lshift(offset) );
  1757.                 break;
  1758.             case (FPTR)MRA_BANK7:
  1759.                 sprintf(dst, "BANK7+%04X", lshift(offset) );
  1760.                 break;
  1761.             case (FPTR)MRA_BANK8:
  1762.                 sprintf(dst, "BANK8+%04X", lshift(offset) );
  1763.                 break;
  1764.             case (FPTR)MRA_NOP:
  1765.                 sprintf(dst, "NOP%d+%04X", nop_cnt, lshift(offset) );
  1766.                 break;
  1767.             default:
  1768.                 if( (FPTR)mr->handler == (FPTR)input_port_0_r )
  1769.                     sprintf(dst, "input_port_0+%04X", lshift(offset) );
  1770.                 else
  1771.                 if( (FPTR)mr->handler == (FPTR)input_port_1_r )
  1772.                     sprintf(dst, "input_port_1+%04X", lshift(offset) );
  1773.                 else
  1774.                 if( (FPTR)mr->handler == (FPTR)input_port_2_r )
  1775.                     sprintf(dst, "input_port_2+%04X", lshift(offset) );
  1776.                 else
  1777.                 if( (FPTR)mr->handler == (FPTR)input_port_3_r )
  1778.                     sprintf(dst, "input_port_3+%04X", lshift(offset) );
  1779.                 else
  1780.                 if( (FPTR)mr->handler == (FPTR)input_port_4_r )
  1781.                     sprintf(dst, "input_port_4+%04X", lshift(offset) );
  1782.                 else
  1783.                 if( (FPTR)mr->handler == (FPTR)input_port_5_r )
  1784.                     sprintf(dst, "input_port_5+%04X", lshift(offset) );
  1785.                 else
  1786.                 if( (FPTR)mr->handler == (FPTR)input_port_6_r )
  1787.                     sprintf(dst, "input_port_6+%04X", lshift(offset) );
  1788.                 else
  1789.                 if( (FPTR)mr->handler == (FPTR)input_port_7_r )
  1790.                     sprintf(dst, "input_port_7+%04X", lshift(offset) );
  1791.                 else
  1792.                 if( (FPTR)mr->handler == (FPTR)input_port_8_r )
  1793.                     sprintf(dst, "input_port_8+%04X", lshift(offset) );
  1794.                 else
  1795.                 if( (FPTR)mr->handler == (FPTR)input_port_9_r )
  1796.                     sprintf(dst, "input_port_9+%04X", lshift(offset) );
  1797.                 else
  1798.                 if( (FPTR)mr->handler == (FPTR)input_port_10_r )
  1799.                     sprintf(dst, "input_port_10+%04X", lshift(offset) );
  1800.                 else
  1801.                 if( (FPTR)mr->handler == (FPTR)input_port_11_r )
  1802.                     sprintf(dst, "input_port_11+%04X", lshift(offset) );
  1803.                 else
  1804.                 if( (FPTR)mr->handler == (FPTR)input_port_12_r )
  1805.                     sprintf(dst, "input_port_12+%04X", lshift(offset) );
  1806.                 else
  1807.                 if( (FPTR)mr->handler == (FPTR)input_port_13_r )
  1808.                     sprintf(dst, "input_port_13+%04X", lshift(offset) );
  1809.                 else
  1810.                 if( (FPTR)mr->handler == (FPTR)input_port_14_r )
  1811.                     sprintf(dst, "input_port_14+%04X", lshift(offset) );
  1812.                 else
  1813.                 if( (FPTR)mr->handler == (FPTR)input_port_15_r )
  1814.                     sprintf(dst, "input_port_15+%04X", lshift(offset) );
  1815.             }
  1816.         }
  1817.         switch( (FPTR)mr->handler )
  1818.         {
  1819.             case (FPTR)MRA_RAM: ram_cnt++; break;
  1820.             case (FPTR)MRA_NOP: nop_cnt++; break;
  1821.         }
  1822.         mr++;
  1823.     }
  1824.  
  1825.     return dst;
  1826. }
  1827.  
  1828. /**************************************************************************
  1829.  * name_wrmem
  1830.  * Find a descriptive name for the given memory write region of activecpu
  1831.  **************************************************************************/
  1832. static const char *name_wrmem( unsigned base )
  1833. {
  1834.     static char buffer[16][79+1];
  1835.     static int which = 0;
  1836.     const struct MachineCPU *cpu = &Machine->drv->cpu[activecpu];
  1837.     const struct MemoryWriteAddress *mw = cpu->memory_write;
  1838.     int ram_cnt = 1, nop_cnt = 1;
  1839.     const char *name;
  1840.     char *dst;
  1841.  
  1842.     which = ++which % 16;
  1843.     dst = buffer[which];
  1844.     *dst = '\0';
  1845.  
  1846.     ram_cnt = nop_cnt = 1;
  1847.     while( *dst == '\0' && mw->start != -1 )
  1848.     {
  1849.         if( base >= mw->start && base <= mw->end )
  1850.         {
  1851. //            if( mw->description )
  1852. //                sprintf(dst, "%s+%04X", mw->description, lshift(base - mw->start) );
  1853. //            else
  1854.             if( mw->base && *mw->base == videoram )
  1855.                 sprintf(dst, "video+%04X", lshift(base - mw->start) );
  1856.             else
  1857.             if( mw->base && *mw->base == colorram )
  1858.                 sprintf(dst, "color+%04X", lshift(base - mw->start) );
  1859.             else
  1860.             if( mw->base && *mw->base == spriteram )
  1861.                 sprintf(dst, "sprite+%04X", lshift(base - mw->start) );
  1862.             else
  1863.             switch( (FPTR)mw->handler )
  1864.             {
  1865.             case (FPTR)MWA_RAM:
  1866.                 sprintf(dst, "RAM%d+%04X", ram_cnt, lshift(base - mw->start) );
  1867.                 break;
  1868.             case (FPTR)MWA_ROM:
  1869.                 name = name_rom("ROM", REGION_CPU1+activecpu, &base, mw->start );
  1870.                 sprintf(dst, "%s+%04X", name, lshift(base) );
  1871.                 break;
  1872.             case (FPTR)MWA_RAMROM:
  1873.                 name = name_rom("RAMROM", REGION_CPU1+activecpu, &base, mw->start);
  1874.                 sprintf(dst, "%s+%04X", name, lshift(base) );
  1875.                 break;
  1876.             case (FPTR)MWA_BANK1:
  1877.                 sprintf(dst, "BANK1+%04X", lshift(base - mw->start) );
  1878.                 break;
  1879.             case (FPTR)MWA_BANK2:
  1880.                 sprintf(dst, "BANK2+%04X", lshift(base - mw->start) );
  1881.                 break;
  1882.             case (FPTR)MWA_BANK3:
  1883.                 sprintf(dst, "BANK3+%04X", lshift(base - mw->start) );
  1884.                 break;
  1885.             case (FPTR)MWA_BANK4:
  1886.                 sprintf(dst, "BANK4+%04X", lshift(base - mw->start) );
  1887.                 break;
  1888.             case (FPTR)MWA_BANK5:
  1889.                 sprintf(dst, "BANK5+%04X", lshift(base - mw->start) );
  1890.                 break;
  1891.             case (FPTR)MWA_BANK6:
  1892.                 sprintf(dst, "BANK6+%04X", lshift(base - mw->start) );
  1893.                 break;
  1894.             case (FPTR)MWA_BANK7:
  1895.                 sprintf(dst, "BANK7+%04X", lshift(base - mw->start) );
  1896.                 break;
  1897.             case (FPTR)MWA_BANK8:
  1898.                 sprintf(dst, "BANK8+%04X", lshift(base - mw->start) );
  1899.                 break;
  1900.             case (FPTR)MWA_NOP:
  1901.                 sprintf(dst, "NOP%d+%04X", nop_cnt, lshift(base - mw->start) );
  1902.                 break;
  1903.             }
  1904.         }
  1905.         switch( (FPTR)mw->handler )
  1906.         {
  1907.             case (FPTR)MRA_RAM: ram_cnt++; break;
  1908.             case (FPTR)MRA_NOP: nop_cnt++; break;
  1909.         }
  1910.         mw++;
  1911.     }
  1912.  
  1913.     return dst;
  1914. }
  1915.  
  1916. /**************************************************************************
  1917.  * name_memory
  1918.  * Find a descriptive name for the given memory region of activecpu
  1919.  **************************************************************************/
  1920. static const char *name_memory( unsigned base )
  1921. {
  1922.     static char buffer[8][79+1];
  1923.     static int which = 0;
  1924.     const char *rd, *wr;
  1925.  
  1926.     /* search readmem and writemem names */
  1927.     rd = name_rdmem( base );
  1928.     wr = name_wrmem( base );
  1929.  
  1930.     /* both empty, so it's no specific region */
  1931.     if( *rd == '\0' && *wr == '\0' )
  1932.     {
  1933.         which = ++which % 8;
  1934.         sprintf(buffer[which], "N/A:%04X", base);
  1935.         return buffer[which];
  1936.     }
  1937.  
  1938.     which = ++which % 8;
  1939.  
  1940.     /* both names differ? */
  1941.     if( strcmp(rd,wr) )
  1942.         /* well, return one of the names... */
  1943.         sprintf(buffer[which], "%s\t%s", rd, wr);
  1944.     else
  1945.         /* return the name for readmem... */
  1946.         sprintf(buffer[which], "%s", rd);
  1947.  
  1948.     return buffer[which];
  1949. }
  1950.  
  1951. /**************************************************************************
  1952.  * win_create
  1953.  * Wrapper function to fill a struct sWindow and call win_open()
  1954.  **************************************************************************/
  1955. static int win_create(int n, UINT8 prio, int x, int y, int w, int h,
  1956.     UINT8 co_text, UINT8 co_frame, UINT8 chr, UINT32 attributes)
  1957. {
  1958.     struct sWindow win;
  1959.     /* fill in the default values for window creation */
  1960.     memset( &win, 0, sizeof(struct sWindow) );
  1961.     win.filler = chr;
  1962.     win.prio = prio;
  1963.     win.x = x;
  1964.     win.y = y;
  1965.     win.w = w;
  1966.     win.h = h;
  1967.     win.flags = NO_SCROLL | NO_WRAP | BORDER_TOP | ((n)? HIDDEN : 0) | attributes;
  1968.     win.co_text = co_text;
  1969.     win.co_frame = co_frame;
  1970.     win.co_title = cur_col[E_TITLE];
  1971.     win.saved_text = ' ';
  1972.     win.saved_attr = WIN_WHITE;
  1973.     return win_open(n, &win);
  1974. }
  1975.  
  1976. static int DECL_SPEC win_msgbox( UINT8 color, const char *title, const char *fmt, ... )
  1977. {
  1978.     UINT32 win = WIN_MSGBOX;
  1979.     va_list arg;
  1980.     int i;
  1981.  
  1982.     win_create( win, 0,
  1983.         4,6,60,3, color, cur_col[E_FRAME], ' ',
  1984.         BORDER_TOP | BORDER_LEFT | BORDER_RIGHT | BORDER_BOTTOM | SHADOW );
  1985.     win_set_title( win, title );
  1986.  
  1987.     va_start( arg, fmt );
  1988.     win_vprintf( win, fmt, arg );
  1989.     va_end( arg );
  1990.  
  1991.     win_show( win );
  1992.     i = keyboard_read_sync();
  1993.     win_close( win );
  1994.  
  1995.     return i;
  1996. }
  1997.  
  1998. /**************************************************************************
  1999.  * dbg_set_rect
  2000.  * set a rectangle from x,y,w and h
  2001.  **************************************************************************/
  2002. INLINE void dbg_set_rect( struct rectangle *r, int x, int y, int w, int h )
  2003. {
  2004.     r->min_x = x;
  2005.     r->max_x = x + w - 1;
  2006.     r->min_y = y;
  2007.     r->max_y = y + h - 1;
  2008. }
  2009.  
  2010. /**************************************************************************
  2011.  * dbg_open_windows
  2012.  * Depending on the CPU type, create a window layout specified
  2013.  * by the CPU core - returned by function cputype_win_layout()
  2014.  **************************************************************************/
  2015. static void dbg_open_windows( void )
  2016. {
  2017.     UINT32 flags;
  2018.     UINT32 i, w, h, aw, ah;
  2019.  
  2020.     /* Initialize windowing engine */
  2021.     osd_get_screen_size( &w, &h );
  2022.     win_init_engine( w, h );
  2023.  
  2024.     /* anything more than 80x25 available? */
  2025.     aw = w - 80;
  2026.     ah = h - 25;
  2027.  
  2028.     for( i = 0; i < totalcpu; i++ )
  2029.     {
  2030.         const UINT8 *win_layout = (UINT8*)cpunum_win_layout(i);
  2031.         struct rectangle regs, dasm, mem1, mem2, cmds;
  2032.  
  2033.         #define REGS_X  win_layout[0*4+0]
  2034.         #define REGS_Y    win_layout[0*4+1]
  2035.         #define REGS_W    win_layout[0*4+2]
  2036.         #define REGS_H    win_layout[0*4+3]
  2037.         #define DASM_X    win_layout[1*4+0]
  2038.         #define DASM_Y    win_layout[1*4+1]
  2039.         #define DASM_W    win_layout[1*4+2]
  2040.         #define DASM_H    win_layout[1*4+3]
  2041.         #define MEM1_X    win_layout[2*4+0]
  2042.         #define MEM1_Y    win_layout[2*4+1]
  2043.         #define MEM1_W    win_layout[2*4+2]
  2044.         #define MEM1_H    win_layout[2*4+3]
  2045.         #define MEM2_X    win_layout[3*4+0]
  2046.         #define MEM2_Y    win_layout[3*4+1]
  2047.         #define MEM2_W    win_layout[3*4+2]
  2048.         #define MEM2_H    win_layout[3*4+3]
  2049.         #define CMDS_X    win_layout[4*4+0]
  2050.         #define CMDS_Y    win_layout[4*4+1]
  2051.         #define CMDS_W    win_layout[4*4+2]
  2052.         #define CMDS_H    win_layout[4*4+3]
  2053.  
  2054.         /* cmds window is fixed w and h, always at the bottom */
  2055.         dbg_set_rect(&cmds, CMDS_X,CMDS_Y+ah,CMDS_W+aw,CMDS_H);
  2056.         if( DASM_Y == 0 )
  2057.         {
  2058.             if( DASM_H + 1 == CMDS_Y )
  2059.             {
  2060.                 /********************
  2061.                  * dasm   * regs    *
  2062.                  *          ***********
  2063.                  *          * mem1    *
  2064.                  *          ***********
  2065.                  *          * mem2    *
  2066.                  ********************
  2067.                  * cmds             *
  2068.                  ********************/
  2069.                  dbg_set_rect(®s, REGS_X+aw,REGS_Y,REGS_W,REGS_H);
  2070.                  dbg_set_rect(&dasm, DASM_X,DASM_Y,DASM_W+aw,DASM_H+ah);
  2071.                  dbg_set_rect(&mem1, MEM1_X+aw,MEM1_Y,MEM1_W,MEM1_H+(ah+1)/2);
  2072.                  dbg_set_rect(&mem2, MEM2_X+aw,MEM2_Y+(ah+1)/2,MEM2_W,MEM2_H+ah/2);
  2073.             }
  2074.             else
  2075.             if( MEM1_X == MEM2_X )
  2076.             {
  2077.                 /********************
  2078.                  * dasm   * regs    *
  2079.                  **********         *
  2080.                  * mem1   *         *
  2081.                  **********         *
  2082.                  * mem2   *         *
  2083.                  ********************
  2084.                  * cmds             *
  2085.                  ********************/
  2086.                  dbg_set_rect(®s, REGS_X+aw,REGS_Y,REGS_W,REGS_H);
  2087.                  dbg_set_rect(&dasm, DASM_X,DASM_Y,DASM_W+aw,DASM_H);
  2088.                  dbg_set_rect(&mem1, MEM1_X,MEM1_Y,MEM1_W+aw,MEM1_H+(ah+1)/2);
  2089.                  dbg_set_rect(&mem2, MEM2_X,MEM2_Y+(ah+1)/2,MEM2_W+aw,MEM2_H+ah/2);
  2090.             }
  2091.             else
  2092.             {
  2093.                 /********************
  2094.                  * dasm   * regs    *
  2095.                  *          *         *
  2096.                  *          *         *
  2097.                  ********************
  2098.                  * mem1   * mem2    *
  2099.                  ********************
  2100.                  * cmds             *
  2101.                  ********************/
  2102.                  dbg_set_rect(®s, REGS_X+aw,REGS_Y,REGS_W,REGS_H);
  2103.                  dbg_set_rect(&dasm, DASM_X,DASM_Y,DASM_W+aw,DASM_H+(ah+1)/2);
  2104.                  dbg_set_rect(&mem1, MEM1_X,MEM1_Y+(ah+1)/2,MEM1_W+aw,MEM1_H+ah/2);
  2105.                  dbg_set_rect(&mem2, MEM2_X+aw,MEM2_Y,MEM2_W,MEM2_H+ah);
  2106.             }
  2107.         }
  2108.         else
  2109.         {
  2110.             /********************
  2111.              * regs             *
  2112.              ********************
  2113.              * dasm   * mem1    *
  2114.              *          ***********
  2115.              *          * mem2    *
  2116.              ********************
  2117.              * cmds             *
  2118.              ********************/
  2119.              dbg_set_rect(®s, REGS_X,REGS_Y,REGS_W+aw,REGS_H);
  2120.              dbg_set_rect(&dasm, DASM_X,DASM_Y,DASM_W+(aw+1)/2,DASM_H+ah);
  2121.              dbg_set_rect(&mem1, MEM1_X+(aw+1)/2,MEM1_Y,MEM1_W+aw/2,MEM1_H+(ah+1)/2);
  2122.              dbg_set_rect(&mem2, MEM2_X+(aw+1)/w,MEM2_Y+(ah+1)/2,MEM2_W+aw/2,MEM2_H+ah/2);
  2123.         }
  2124.  
  2125.         flags = BORDER_TOP;
  2126.         if( regs.max_x + 1 < w ) flags |= BORDER_RIGHT;
  2127.         win_create(WIN_REGS(i), 1,
  2128.             regs.min_x,regs.min_y,
  2129.             regs.max_x+1-regs.min_x,regs.max_y+1-regs.min_y,
  2130.             cur_col[E_REGS], cur_col[E_FRAME], ' ', flags );
  2131.  
  2132.         flags = BORDER_TOP | BORDER_RIGHT;
  2133.         win_create(WIN_DASM(i), 1,
  2134.             dasm.min_x, dasm.min_y,
  2135.             dasm.max_x+1-dasm.min_x,dasm.max_y+1-dasm.min_y,
  2136.             cur_col[E_DASM], cur_col[E_FRAME], ' ', flags );
  2137.  
  2138.         flags = BORDER_TOP;
  2139.         if( mem1.max_x + 1 < w ) flags |= BORDER_RIGHT;
  2140.         win_create(WIN_MEM1(i), 1,
  2141.             mem1.min_x,mem1.min_y,
  2142.             mem1.max_x+1-mem1.min_x,mem1.max_y+1-mem1.min_y,
  2143.             cur_col[E_MEM1], cur_col[E_FRAME], ' ', flags );
  2144.  
  2145.         flags = BORDER_TOP;
  2146.         if( mem2.max_x + 1 < w) flags |= BORDER_RIGHT;
  2147.         win_create(WIN_MEM2(i), 1,
  2148.             mem2.min_x,mem2.min_y,
  2149.             mem2.max_x+1-mem2.min_x,mem2.max_y+1-mem2.min_y,
  2150.             cur_col[E_MEM2], cur_col[E_FRAME], ' ', flags );
  2151.  
  2152.         flags = BORDER_TOP;
  2153.         win_create(WIN_CMDS(i), 1,
  2154.             cmds.min_x,cmds.min_y,
  2155.             cmds.max_x+1-cmds.min_x,cmds.max_y+1-cmds.min_y,
  2156.             cur_col[E_CMDS], cur_col[E_FRAME], ' ', flags );
  2157.  
  2158.         win_set_title(WIN_CMDS(i), "Command (press F1 for help)");
  2159.     }
  2160. }
  2161.  
  2162. /**************************************************************************
  2163.  * dbg_close_windows
  2164.  * Close all windows and shut down the window engine
  2165.  **************************************************************************/
  2166. static void dbg_close_windows( void )
  2167. {
  2168.     int i;
  2169.  
  2170.     for( i = 0; i < totalcpu; i++ )
  2171.     {
  2172.         win_close( WIN_REGS(i) );
  2173.         win_close( WIN_DASM(i) );
  2174.         win_close( WIN_MEM1(i) );
  2175.         win_close( WIN_MEM2(i) );
  2176.         win_close( WIN_CMDS(i) );
  2177.     }
  2178.     win_exit_engine();
  2179. }
  2180.  
  2181. /**************************************************************************
  2182.  * dasm_line
  2183.  * disassemble <times> instructions from pc and return the final pc
  2184.  **************************************************************************/
  2185. static unsigned dasm_line( unsigned pc, int times )
  2186. {
  2187.     static char buffer[127+1];
  2188.  
  2189.     while( times-- > 0 )
  2190.         pc += cpu_dasm( buffer, pc );
  2191.     pc = lshift( rshift(pc) & AMASK );
  2192.  
  2193.     return pc;
  2194. }
  2195.  
  2196.  
  2197. /**************************************************************************
  2198.  * dump_regs
  2199.  * Update the register display
  2200.  * Compare register values against the ones stored in reg->backup[]
  2201.  * Store new values in reg->newval[] which is copied to reg->backup[]
  2202.  * before the next instruction is executed (at the end of MAME_Debug).
  2203.  **************************************************************************/
  2204. static void dump_regs( void )
  2205. {
  2206.     char title[80+1];
  2207.     UINT32 win = WIN_REGS(activecpu);
  2208.     s_regs *regs = &DBGREGS;
  2209.     s_edit *pedit = regs->edit;
  2210.     UINT32 *old = regs->backup;
  2211.     UINT32 *val = regs->newval;
  2212.     UINT32 width;
  2213.     const char *name = cpu_name(), *flags = cpu_flags();
  2214.     int w = win_get_w(win);
  2215.     int h = win_get_h(win);
  2216.     int i, j, l, x, y;
  2217.     UINT8 color;
  2218.     const INT8 *reg = (INT8*)cpu_reg_layout();
  2219.  
  2220.     /* Called the very first time: find max_width */
  2221.     if( regs->count == 0 )
  2222.     {
  2223.         for(i = 0; reg[i]; i++)
  2224.         {
  2225.             if( reg[i] == -1 )
  2226.                 continue;        /* skip row breaks */
  2227.             width = strlen( cpu_dump_reg(reg[i]) );
  2228.             if( width >= regs->max_width )
  2229.                 regs->max_width = width + 1;
  2230.         }
  2231.     }
  2232.  
  2233.     x = 0;
  2234.     y = 0;
  2235.     win_set_curpos( win, 0, 0 );
  2236.     sprintf( title, "CPU #%d %-8s Flags:%s  Cycles:%6u", activecpu, name, flags, cpu_geticount() );
  2237.     l = strlen(title);
  2238.     if( l + 2 < w )
  2239.     {
  2240.         /* Everything should fit into the caption */
  2241.         if( l + 4 < w )
  2242.             /* We can even separate the cycles to the right corner */
  2243.             sprintf( title, "CPU #%d %-8s Flags:%s\tCycles:%6u", activecpu, name, flags, cpu_geticount() );
  2244.         win_set_title( win, title );
  2245.     }
  2246.     else
  2247.     {
  2248.         /* At least CPU # and flags should fit into the caption */
  2249.         sprintf( title, "CPU #%d %-8s Flags:%s", activecpu, name, flags );
  2250.         l = strlen(title);
  2251.         if( l + 2 < w )
  2252.         {
  2253.             if( l + 4 < w )
  2254.                 sprintf( title, "CPU #%d %-8s\tFlags:%s", activecpu, name, flags );
  2255.             win_set_title( win, title );
  2256.             if( y < h )
  2257.             {
  2258.                 win_printf( win, "Cycles:%6u\n", cpu_geticount() );
  2259.             }
  2260.         }
  2261.         else
  2262.         {
  2263.             sprintf( title, "CPU #%d %-8s Cyc:%6u", activecpu, name, cpu_geticount() );
  2264.             l = strlen(title);
  2265.             if( l + 2 < w )
  2266.             {
  2267.                 if( l + 4 < w )
  2268.                     sprintf( title, "CPU #%d %-8s\tCyc:%6u", activecpu, name, cpu_geticount() );
  2269.                 win_set_title( win, title );
  2270.                 if( y < h )
  2271.                 {
  2272.                     if( strlen(cpu_flags()) + 8 < w )
  2273.                         win_printf( win, "Flags: %s\n", flags );
  2274.                     else
  2275.                     if( strlen(cpu_flags()) + 2 < w )
  2276.                         win_printf( win, "F:%s\n", flags );
  2277.                     else
  2278.                         win_printf( win, "%s\n", flags );
  2279.                 }
  2280.             }
  2281.             else
  2282.             {
  2283.                 /* Only CPU # and name fit into the caption */
  2284.                 sprintf( title, "CPU #%d %-8s", activecpu, name );
  2285.                 l = strlen(title);
  2286.                 win_set_title( win, title );
  2287.                 if( y < h )
  2288.                 {
  2289.                 if( strlen(cpu_flags()) + 8 < w )
  2290.                     win_printf( win, "Flags: %s\n", flags );
  2291.                 else
  2292.                 if( strlen(cpu_flags()) + 2 < w )
  2293.                     win_printf( win, "F:%s\n", flags );
  2294.                 else
  2295.                     win_printf( win, "%s\n", flags );
  2296.                 }
  2297.                 y++;
  2298.                 win_printf( win, "Cycles:%6u\n", cpu_geticount() );
  2299.             }
  2300.             y++;
  2301.         }
  2302.     }
  2303.     regs->top = y;
  2304.     y = 0;
  2305.  
  2306.     for( i = 0, j = 0; *reg; i++, reg++ )
  2307.     {
  2308.         if( *reg == -1 )
  2309.         {
  2310.             if( y >= regs->base && y < regs->base + h - regs->top )
  2311.             {
  2312.                 win_erase_eol( win, ' ' );
  2313.                 win_putc( win, '\n');
  2314.             }
  2315.             x = 0;
  2316.             y++;
  2317.         }
  2318.         else
  2319.         {
  2320.             name = cpu_dump_reg(*reg);
  2321.             if( *name == '\0' )
  2322.                 continue;
  2323.  
  2324.             regs->id[j] = *reg;
  2325.             *val = cpu_get_reg(regs->id[j]);
  2326.             color = cur_col[E_REGS];
  2327.             if( DBG.brk_regs == *reg )
  2328.                 color = cur_col[E_BRK_REGS];
  2329.             if( *val != *old )
  2330.             {
  2331.                 regs->changed = 1;
  2332.                 color = (color & 0xf0) | cur_col[E_CHANGES];
  2333.             }
  2334.             win_set_color( win, color );
  2335.  
  2336.             /* edit structure not yet initialized? */
  2337.             if( regs->count == 0 )
  2338.             {
  2339.                 char *p;
  2340.                 /* Get the cursor position */
  2341.                 pedit->x = x;
  2342.                 pedit->y = y + regs->base;
  2343.                 strncpy( regs->name[j], name, sizeof(regs->name[j]) - 1 );
  2344.                 if( strlen(name) >= regs->max_width )
  2345.                     regs->max_width = strlen(name) + 1;
  2346.                 /* Find a colon */
  2347.                 p = strchr( regs->name[j], ':');
  2348.                 if( p )
  2349.                 {
  2350.                     pedit->w = strlen( p + 1 );
  2351.                 }
  2352.                 else
  2353.                 {
  2354.                     /* Or else find an apostrophe */
  2355.                     p = strchr( regs->name[j], '\'' );
  2356.                     if( p )
  2357.                     {
  2358.                         /* Include the apostrophe in the name! */
  2359.                         ++p;
  2360.                         pedit->w = strlen( p );
  2361.                     }
  2362.                 }
  2363.                 /* TODO: other characters to delimit a register name from it's value? */
  2364.                 if( p )
  2365.                 {
  2366.                     /* length of the name (total length - length of nibbles) */
  2367.                     pedit->n = strlen( name ) - pedit->w;
  2368.                     /* terminate name at (or after) the delimiting character */
  2369.                     *p = '\0';
  2370.                     /* eventually strip trailing spaces */
  2371.                     while( *--p == ' ' ) *p = '\0';
  2372.                 }
  2373.                 else
  2374.                 {
  2375.                     /* this is certainly wrong :( */
  2376.                     pedit->w = strlen(regs->name[j]);
  2377.                     pedit->n = 0;
  2378.                 }
  2379.             }
  2380.             if( y >= regs->base && y < regs->base + h - regs->top )
  2381.             {
  2382.                 win_printf( win, "%s", name );
  2383.  
  2384.                 win_set_color( win, cur_col[E_REGS] );
  2385.                 /* If no row break follows, advance to the next tab stop */
  2386.                 if( reg[1] != -1 )
  2387.                     win_printf( win, "%*s", regs->max_width - pedit->w - pedit->n, "" );
  2388.             }
  2389.             x += strlen( name ) + regs->max_width - pedit->w - pedit->n;
  2390.             pedit++;
  2391.             val++;
  2392.             old++;
  2393.             j++;
  2394.         }
  2395.     }
  2396.     while( y >= regs->base && y < regs->base + h - regs->top )
  2397.     {
  2398.         win_erase_eol( win, ' ' );
  2399.         win_putc( win, '\n' );
  2400.         y++;
  2401.     }
  2402.  
  2403.     /* Set the total count of registers */
  2404.     regs->count = j;
  2405. }
  2406.  
  2407. /**************************************************************************
  2408.  * dump_dasm
  2409.  * Update the disassembly display
  2410.  **************************************************************************/
  2411. static unsigned dump_dasm( unsigned pc )
  2412. {
  2413.     UINT32 win = WIN_DASM(activecpu);
  2414.     int w = win_get_w(win);
  2415.     int h = win_get_h(win);
  2416.     int x, y, l, line_pc_cpu = INVALID, line_pc_cur = INVALID;
  2417.     UINT8 color;
  2418.     char dasm[127+1];
  2419.     unsigned pc_first = pc, pc_next;
  2420.     unsigned width = (ABITS + 3) / 4;
  2421.  
  2422.     while( line_pc_cpu == INVALID )
  2423.     {
  2424.         pc = pc_first;
  2425.  
  2426.         for( y = 0; y < h; y++ )
  2427.         {
  2428.             win_set_curpos( win, 0, y );
  2429.             if( pc == DBG.brk_exec )
  2430.                 color = cur_col[E_BRK_EXEC];
  2431.             else
  2432.                 color = cur_col[E_DASM];
  2433.             if( pc == DBGDASM.pc_cpu )
  2434.             {
  2435.                 color = (color & 0x0f) | (cur_col[E_PC] & 0xf0);
  2436.                 line_pc_cpu = y;
  2437.             }
  2438.             if( pc == DBGDASM.pc_cur )
  2439.             {
  2440.                 color = (color & 0x0f) | (cur_col[E_CURSOR] & 0xf0);
  2441.                 line_pc_cur = y;
  2442.             }
  2443.             win_set_color( win, color );
  2444.             l = win_printf( win, "%0*X: ", width, pc );
  2445.  
  2446.             DBGDASM.dst_ea_value = INVALID;
  2447.             DBGDASM.src_ea_value = INVALID;
  2448.             pc_next = pc + cpu_dasm( dasm, pc );
  2449.  
  2450.             if( DBGDASM.pc_cur == pc )
  2451.                 win_set_title( win, "%s", get_ea_info(pc) );
  2452.  
  2453.             if( dbg_dasm_opcodes )
  2454.             {
  2455.                 unsigned p = rshift(pc);
  2456.                 unsigned n = rshift(pc_next);
  2457.                 switch( ALIGN )
  2458.                 {
  2459.                 case 1:
  2460.                     for( x = 0; x < INSTL; x++ )
  2461.                     {
  2462.                         if ( p < n )
  2463.                         {
  2464.                             l += win_printf( win, "%02X ",
  2465.                                 RDMEM(order(p,1)) );
  2466.                             p++;
  2467.                         }
  2468.                         else l += win_printf( win, "   " );
  2469.                     }
  2470.                     break;
  2471.                 case 2:
  2472.                     for( x = 0; x < INSTL; x += 2 )
  2473.                     {
  2474.                         if ( p < n )
  2475.                         {
  2476.                             l += win_printf( win, "%02X%02X ",
  2477.                                 RDMEM(order(p+0,2)), RDMEM(order(p+1,2)) );
  2478.                             p += 2;
  2479.                         }
  2480.                         else l += win_printf( win, "     " );
  2481.                     }
  2482.                     break;
  2483.                 case 4:
  2484.                     for( x = 0; x < INSTL; x += 4 )
  2485.                     {
  2486.                         if ( p < n)
  2487.                         {
  2488.                             l += win_printf( win, "%02X%02X%02X%02X ",
  2489.                                 RDMEM(order(p+0,4)), RDMEM(order(p+1,4)),
  2490.                                 RDMEM(order(p+2,4)), RDMEM(order(p+3,4)) );
  2491.                             p += 4;
  2492.                         }
  2493.                         else l += win_printf( win, "         " );
  2494.                     }
  2495.                     break;
  2496.                 }
  2497.             }
  2498.             pc = lshift(rshift(pc_next) & AMASK);
  2499.             switch( dbg_dasm_case )
  2500.             {
  2501.                 case 0: win_printf( win, "%-*.*s", w-l, w-l, dasm ); break;
  2502.                 case 1: win_printf( win, "%-*.*s", w-l, w-l, lower(dasm) ); break;
  2503.                 case 2: win_printf( win, "%-*.*s", w-l, w-l, upper(dasm) ); break;
  2504.             }
  2505.         }
  2506.         if( line_pc_cpu == INVALID )
  2507.         {
  2508.             /*
  2509.              * We didn't find the exact instruction of the CPU PC.
  2510.              * This has to be caused by a jump into the midst of
  2511.              * another instruction down from the top. If the CPU PC
  2512.              * is between pc_first and pc (end), try again on next
  2513.              * instruction size boundary, else bail out...
  2514.              */
  2515.             if( DBGDASM.pc_cpu > pc_first && DBGDASM.pc_cpu < pc )
  2516.                 pc_first += ALIGN;
  2517.             else
  2518.                 line_pc_cpu = 0;
  2519.         }
  2520.     }
  2521.  
  2522.     win_set_curpos( win, 0, line_pc_cur );
  2523.  
  2524.     return pc;
  2525. }
  2526.  
  2527. /**************************************************************************
  2528.  * dump_mem_hex
  2529.  * Update a memory window using the cpu_readmemXXX function
  2530.  * Changed values are displayed using foreground color cur_col[E_CHANGES]
  2531.  * The new values are stored into mem->newval[] of the activecpu
  2532.  **************************************************************************/
  2533. static void dump_mem_hex( int which, unsigned len_addr, unsigned len_data )
  2534. {
  2535.     UINT32 win = WIN_MEM(activecpu,which);
  2536.     s_edit *pedit = DBGMEM[which].edit;
  2537.     int w = win_get_w(win);
  2538.     int h = win_get_h(win);
  2539.     UINT8 *old = DBGMEM[which].backup;
  2540.     UINT8 *val = DBGMEM[which].newval;
  2541.     UINT8 color, dim_bright = 0;
  2542.     UINT8 spc_left = 0;     /* assume no space left of address */
  2543.     UINT8 spc_addr = 0;     /* assume no space after address */
  2544.     UINT8 spc_data = 1;     /* assume one space between adjacent data elements */
  2545.     UINT8 spc_hyphen = 0;    /* assume no space around center hyphen */
  2546.     unsigned offs, column;
  2547.  
  2548.     /* how many elements (bytes,words,dwords) will fit in a line? */
  2549.     DBGMEM[which].width = (w - len_addr - 1) / (len_data + spc_data);
  2550.  
  2551.     /* display multiples of eight bytes per line only */
  2552.     if( DBGMEM[which].width > ((16/len_data)-1) )
  2553.         DBGMEM[which].width &= ~((16/len_data)-1);
  2554.  
  2555.     /* Is bytes per line not divideable by eight? */
  2556.     if( dbg_mem_squeezed && (DBGMEM[which].width & 7) )
  2557.     {
  2558.         /* We try an alternating dim,bright layout w/o data spacing */
  2559.         spc_data = 0;
  2560.         /* how many bytes will fit in a line? */
  2561.         DBGMEM[which].width = (w - len_addr - 1) / len_data;
  2562.         /* display multiples of eight data elements per line only */
  2563.         if( DBGMEM[which].width > ((16/len_data)-1) )
  2564.             DBGMEM[which].width &= ~((16/len_data)-1);
  2565.         dim_bright = 0x08;
  2566.     }
  2567.  
  2568.     /* calculate number of bytes per line */
  2569.     DBGMEM[which].bytes = DBGMEM[which].width * len_data / 2;
  2570.     /* calculate the DBGMEM[which].size using that data width */
  2571.     DBGMEM[which].size = DBGMEM[which].bytes * h;
  2572.  
  2573.     /* will a space after the address fit into the line? */
  2574.     if( ( len_addr + spc_addr + DBGMEM[which].width * (len_data + spc_data) + 1 ) < w )
  2575.         spc_addr = 1;
  2576.  
  2577.     /* will two spaces around the center hyphen fit into the line ? */
  2578.     if( ( len_addr + spc_addr + DBGMEM[which].width * (len_data + spc_data) + 2 ) < w )
  2579.         spc_hyphen = 1;
  2580.  
  2581.     while( ( 2*spc_left + len_addr + spc_addr + DBGMEM[which].width * (len_data + spc_data) - 1 + spc_hyphen ) + 2 < w )
  2582.         spc_left++;
  2583.  
  2584.     win_set_curpos( win, 0, 0 );
  2585.  
  2586.     for( offs = 0, column = 0; offs < DBGMEM[which].size; offs++, old++, val++ )
  2587.     {
  2588.         color = cur_col[E_MEM1+which];
  2589.         switch( len_data )
  2590.         {
  2591.         case 2: /* UINT8 mode */
  2592.             DBGMEM[which].address = (DBGMEM[which].base + order(offs,1)) & AMASK;
  2593.             break;
  2594.         case 4: /* UINT16 mode */
  2595.             DBGMEM[which].address = (DBGMEM[which].base + order(offs,2)) & AMASK;
  2596.             break;
  2597.         case 8: /* UINT32 mode */
  2598.             DBGMEM[which].address = (DBGMEM[which].base + order(offs,4)) & AMASK;
  2599.             break;
  2600.         }
  2601.  
  2602.         if( column == 0 )
  2603.         {
  2604.             win_set_color( win, cur_col[E_MEM1+which] );
  2605.             win_printf( win, "%*s%0*X:%*s",
  2606.                 spc_left, "", len_addr, lshift((DBGMEM[which].base + offs) & AMASK), spc_addr, "" );
  2607.         }
  2608.  
  2609.         if( DBGMEM[which].address == DBG.brk_data )
  2610.             color = cur_col[E_BRK_DATA];
  2611.  
  2612.         *val = RDMEM( DBGMEM[which].address );
  2613.  
  2614.         if( *val != *old )
  2615.         {
  2616.             DBGMEM[which].changed = 1;
  2617.             color = (color & 0xf0) | (cur_col[E_CHANGES] & 0x0f);
  2618.         }
  2619.  
  2620.         if( (column * 2 / len_data) & 1 )
  2621.             color ^= dim_bright;
  2622.  
  2623.         /* edit structure not yet initialized? */
  2624.         if( pedit->w == 0 )
  2625.         {
  2626.             /* store memory edit x,y */
  2627.             pedit->x = win_get_cx( win );
  2628.             pedit->y = win_get_cy( win );
  2629.             pedit->w = 2;
  2630.             pedit->n = order(column % (len_data / 2), len_data / 2);
  2631.         }
  2632.         pedit++;
  2633.  
  2634.         win_set_color( win, color );
  2635.         switch( DBGMEM[which].ascii )
  2636.         {
  2637.             case 0: /* hex */
  2638.                 win_printf( win, "%02X", *val );
  2639.                 break;
  2640.             case 1: /* translated */
  2641.                 win_printf( win, "%c ", trans_table[*val] );
  2642.                 break;
  2643.             case 2: /* plain character, except for \r, \n and \t */
  2644.                 if( *val == '\0' || *val == '\b' || *val == '\t' ||
  2645.                     *val == '\r' || *val == '\n' )
  2646.                     win_printf( win, ". " );
  2647.                 else
  2648.                     win_printf( win, "%c ", *val );
  2649.                 break;
  2650.         }
  2651.  
  2652.         if( ++column < DBGMEM[which].bytes )
  2653.         {
  2654.             win_set_color( win, cur_col[E_MEM1+which] );
  2655.             if( column == DBGMEM[which].bytes / 2 )
  2656.                 win_printf( win, "%*s-%*s", spc_hyphen, "", spc_hyphen, "" );
  2657.             else
  2658.             if( spc_data && (column * 2 % len_data) == 0 )
  2659.                 win_putc( win, ' ' );
  2660.         }
  2661.         else
  2662.         {
  2663.             win_putc( win, '\n');
  2664.             column = 0;
  2665.         }
  2666.     }
  2667. }
  2668.  
  2669. /**************************************************************************
  2670.  * dump_mem
  2671.  * Update a memory window
  2672.  * Dispatch to one of the memory handler specific output functions
  2673.  **************************************************************************/
  2674. static void dump_mem( int which, int set_title )
  2675. {
  2676.     unsigned len_addr = (ABITS + ASHIFT + 3) / 4;
  2677.  
  2678.     if( set_title )
  2679.         win_set_title( WIN_MEM(activecpu,which), name_memory(DBGMEM[which].base) );
  2680.  
  2681.     switch( DBGMEM[which].mode )
  2682.     {
  2683.         case MODE_HEX_UINT8:  dump_mem_hex( which, len_addr, 2 ); break;
  2684.         case MODE_HEX_UINT16: dump_mem_hex( which, len_addr, 4 ); break;
  2685.         case MODE_HEX_UINT32: dump_mem_hex( which, len_addr, 8 ); break;
  2686.     }
  2687. }
  2688.  
  2689. /**************************************************************************
  2690.  * edit_regs
  2691.  * Edit the registers
  2692.  **************************************************************************/
  2693. static void edit_regs( void )
  2694. {
  2695.     UINT32 win = WIN_REGS(activecpu);
  2696.     s_regs *regs = &DBGREGS;
  2697.     s_edit *pedit = regs->edit;
  2698.     unsigned shift, mask, val;
  2699.     const char *k;
  2700.     int i, x, y;
  2701.  
  2702.     /* Eventually update the cmdline window caption */
  2703.     edit_cmds_info();
  2704.  
  2705.     if( regs->base > pedit[ regs->idx ].y )
  2706.     {
  2707.         regs->base = pedit[ regs->idx ].y;
  2708.         dump_regs();
  2709.     }
  2710.     else
  2711.     if( pedit[ regs->idx ].y >= regs->base + win_get_h( win ) - regs->top )
  2712.     {
  2713.         regs->base = pedit[ regs->idx ].y - win_get_h( win ) + regs->top + 1;
  2714.         dump_regs();
  2715.     }
  2716.     win_set_curpos( win, pedit[regs->idx].x + pedit[regs->idx].n + regs->nibble, pedit[regs->idx].y - regs->base + regs->top );
  2717.     osd_set_screen_curpos( win_get_cx_abs(win), win_get_cy_abs(win) );
  2718.  
  2719.     i = keyboard_read_sync();
  2720.     k = keyboard_name(i);
  2721.  
  2722.     shift = (pedit->w - 1 - regs->nibble) * 4;
  2723.     mask = ~(0x0000000f << shift);
  2724.  
  2725.     if( strlen(k) == 1 )
  2726.     {
  2727.         switch( k[0] )
  2728.         {
  2729.             case '0': case '1': case '2': case '3':
  2730.             case '4': case '5': case '6': case '7':
  2731.             case '8': case '9': case 'A': case 'B':
  2732.             case 'C': case 'D': case 'E': case 'F':
  2733.                 val = k[0] - '0';
  2734.                 if( val > 9 ) val -= 7;
  2735.                 val <<= shift;
  2736.                 /* now modify the register */
  2737.                 cpu_set_reg( regs->id[regs->idx],
  2738.                     ( cpu_get_reg( regs->id[regs->idx] ) & mask ) | val );
  2739.                 dump_regs();
  2740.                 i = KEYCODE_RIGHT;    /* advance to next nibble */
  2741.         }
  2742.     }
  2743.  
  2744.     switch( i )
  2745.     {
  2746.         case KEYCODE_LEFT:
  2747.             if( --regs->nibble < 0 )
  2748.             {
  2749.                 if( --regs->idx < 0 )
  2750.                 {
  2751.                     regs->idx = regs->count - 1;
  2752.                 }
  2753.                 regs->nibble = pedit[regs->idx].w - 1;
  2754.             }
  2755.             break;
  2756.  
  2757.         case KEYCODE_RIGHT:
  2758.             if( ++regs->nibble >= pedit[regs->idx].w )
  2759.             {
  2760.                 regs->nibble = 0;
  2761.                 if( ++regs->idx >= regs->count )
  2762.                 {
  2763.                     regs->idx = 0;
  2764.                 }
  2765.             }
  2766.             break;
  2767.  
  2768.         case KEYCODE_UP:
  2769.             i = regs->idx;
  2770.             x = pedit[regs->idx].x;
  2771.             y = pedit[regs->idx].y;
  2772.             while( x != pedit[i].x || pedit[i].y == y )
  2773.             {
  2774.                 if( --i < 0 )
  2775.                 {
  2776.                     i = regs->count - 1;
  2777.                     if( pedit[i].y == y )
  2778.                     {
  2779.                         i = regs->idx;
  2780.                         break;
  2781.                     }
  2782.                 }
  2783.             }
  2784.             if( i != regs->idx )
  2785.             {
  2786.                 if( regs->nibble >= pedit[i].w )
  2787.                     regs->nibble = pedit[i].w - 1;
  2788.                 regs->idx = i;
  2789.             }
  2790.             break;
  2791.  
  2792.         case KEYCODE_DOWN:
  2793.             i = regs->idx;
  2794.             x = pedit[regs->idx].x;
  2795.             y = pedit[regs->idx].y;
  2796.             while( x != pedit[i].x || pedit[i].y == y )
  2797.             {
  2798.                 if( ++i >= regs->count )
  2799.                 {
  2800.                     i = 0;
  2801.                     if( pedit[i].y == y )
  2802.                     {
  2803.                         i = regs->idx;
  2804.                         break;
  2805.                     }
  2806.                 }
  2807.             }
  2808.             if( i != regs->idx )
  2809.             {
  2810.                 if( regs->nibble >= pedit[i].w )
  2811.                     regs->nibble = pedit[i].w - 1;
  2812.                 regs->idx = i;
  2813.             }
  2814.             break;
  2815.  
  2816.         case KEYCODE_ENTER:
  2817.             DBG.window = EDIT_CMDS;
  2818.             break;
  2819.  
  2820.         default:
  2821.             cmd_default( i );
  2822.     }
  2823. }
  2824.  
  2825.  
  2826. /**************************************************************************
  2827.  * edit_dasm
  2828.  * Edit the disassembly output
  2829.  **************************************************************************/
  2830. static void edit_dasm(void)
  2831. {
  2832.     UINT32 win = WIN_DASM(activecpu);
  2833.     const char *k;
  2834.     int i, update_window = 0;
  2835.  
  2836.     /* Eventually update the cmdline window caption */
  2837.     edit_cmds_info();
  2838.  
  2839.     osd_set_screen_curpos( win_get_cx_abs(win), win_get_cy_abs(win) );
  2840.  
  2841.     i = keyboard_read_sync();
  2842.     k = keyboard_name(i);
  2843.  
  2844.     switch( i )
  2845.     {
  2846.         case KEYCODE_M: /* Toggle mode (opcode display) */
  2847.             sprintf( CMD, "%d", dbg_dasm_opcodes ^ 1 );
  2848.             cmd_set_dasm_opcodes();
  2849.             break;
  2850.  
  2851.         case KEYCODE_D: /* Default case disassembly */
  2852.             dbg_dasm_case = 0;
  2853.             update_window = 1;
  2854.             break;
  2855.  
  2856.         case KEYCODE_L: /* Lower case disassembly */
  2857.             dbg_dasm_case = 1;
  2858.             update_window = 1;
  2859.             break;
  2860.  
  2861.         case KEYCODE_U: /* Upper case disassembly */
  2862.             dbg_dasm_case = 2;
  2863.             update_window = 1;
  2864.             break;
  2865.  
  2866.         case KEYCODE_R: /* Toggle relative jumps display */
  2867.             dbg_dasm_relative_jumps ^= 1;
  2868.             update_window = 1;
  2869.             break;
  2870.  
  2871.         case KEYCODE_ENTER:
  2872.             DBG.window = EDIT_CMDS;
  2873.             break;
  2874.  
  2875.         default:
  2876.             cmd_default( i );
  2877.     }
  2878.     if( update_window )
  2879.     {
  2880.         DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  2881.     }
  2882. }
  2883.  
  2884.  
  2885. /**************************************************************************
  2886.  * edit_mem
  2887.  * Edit the memory dumps output
  2888.  **************************************************************************/
  2889. static void edit_mem( int which )
  2890. {
  2891.     UINT32 win = WIN_MEM(activecpu,which);
  2892.     s_edit *pedit = DBGMEM[which].edit;
  2893.     const char *k;
  2894.     unsigned shift, mask, val;
  2895.     int i, update_window = 0;
  2896.  
  2897.     /* Eventually update the cmdline window caption */
  2898.     edit_cmds_info();
  2899.  
  2900.     win_set_curpos( win, pedit[DBGMEM[which].offset].x + DBGMEM[which].nibble, pedit[DBGMEM[which].offset].y );
  2901.     osd_set_screen_curpos( win_get_cx_abs(win), win_get_cy_abs(win) );
  2902.  
  2903.     switch( DBGMEM[which].mode )
  2904.     {
  2905.         case MODE_HEX_UINT8:
  2906.             DBGMEM[which].address = (DBGMEM[which].base + DBGMEM[which].offset) & AMASK;
  2907.             break;
  2908.         case MODE_HEX_UINT16:
  2909.             DBGMEM[which].address = (DBGMEM[which].base + (DBGMEM[which].offset & ~1) + pedit[DBGMEM[which].offset].n ) & AMASK;
  2910.             break;
  2911.         case MODE_HEX_UINT32:
  2912.             DBGMEM[which].address = (DBGMEM[which].base + (DBGMEM[which].offset & ~3) + pedit[DBGMEM[which].offset].n ) & AMASK;
  2913.             break;
  2914.     }
  2915.     win_set_title( win, name_memory( DBGMEM[which].address ) );
  2916.  
  2917.     i = keyboard_read_sync();
  2918.     k = keyboard_name(i);
  2919.  
  2920.     shift = (pedit[DBGMEM[which].offset].w - 1 - DBGMEM[which].nibble) * 4;
  2921.     mask = ~(0x0f << shift);
  2922.  
  2923.     if( strlen(k) == 1 )
  2924.     {
  2925.         switch( k[0] )
  2926.         {
  2927.             case '0': case '1': case '2': case '3':
  2928.             case '4': case '5': case '6': case '7':
  2929.             case '8': case '9': case 'A': case 'B':
  2930.             case 'C': case 'D': case 'E': case 'F':
  2931.                 val = k[0] - '0';
  2932.                 if( val > 9 ) val -= 7;
  2933.                 val <<= shift;
  2934.                 /* now modify the register */
  2935.                 WRMEM( DBGMEM[which].address, ( RDMEM( DBGMEM[which].address ) & mask ) | val );
  2936.                 update_window = 1;
  2937.                 i = KEYCODE_RIGHT;    /* advance to next nibble */
  2938.         }
  2939.     }
  2940.  
  2941.     switch( i )
  2942.     {
  2943.         case KEYCODE_LEFT:
  2944.             if( --DBGMEM[which].nibble < 0 )
  2945.             {
  2946.                 if( --DBGMEM[which].offset < 0 )
  2947.                 {
  2948.                     DBGMEM[which].base = (DBGMEM[which].base - DBGMEM[which].bytes) & AMASK;
  2949.                     DBGMEM[which].offset += DBGMEM[which].bytes;
  2950.                     update_window = 1;
  2951.                 }
  2952.                 DBGMEM[which].nibble = pedit[DBGMEM[which].offset].w - 1;
  2953.             }
  2954.             break;
  2955.  
  2956.         case KEYCODE_RIGHT:
  2957.             if( ++DBGMEM[which].nibble >= pedit[DBGMEM[which].offset].w )
  2958.             {
  2959.                 DBGMEM[which].nibble = 0;
  2960.                 if( ++DBGMEM[which].offset >= DBGMEM[which].size )
  2961.                 {
  2962.                     DBGMEM[which].base = (DBGMEM[which].base + DBGMEM[which].bytes) & AMASK;
  2963.                     DBGMEM[which].offset -= DBGMEM[which].bytes;
  2964.                     update_window = 1;
  2965.                 }
  2966.             }
  2967.             break;
  2968.  
  2969.         case KEYCODE_UP:
  2970.             DBGMEM[which].offset -= DBGMEM[which].bytes;
  2971.             if( DBGMEM[which].offset < 0 )
  2972.             {
  2973.                 DBGMEM[which].base = (DBGMEM[which].base - DBGMEM[which].bytes) & AMASK;
  2974.                 DBGMEM[which].offset += DBGMEM[which].bytes;
  2975.                 update_window = 1;
  2976.             }
  2977.             break;
  2978.  
  2979.         case KEYCODE_DOWN:
  2980.             DBGMEM[which].offset += DBGMEM[which].bytes;
  2981.             if( DBGMEM[which].offset >= DBGMEM[which].size )
  2982.             {
  2983.                 DBGMEM[which].base = (DBGMEM[which].base + DBGMEM[which].bytes) & AMASK;
  2984.                 DBGMEM[which].offset -= DBGMEM[which].bytes;
  2985.                 update_window = 1;
  2986.             }
  2987.             break;
  2988.  
  2989.         case KEYCODE_PGUP:
  2990.             DBGMEM[which].base = (DBGMEM[which].base - DBGMEM[which].size) & AMASK;
  2991.             update_window = 1;
  2992.             break;
  2993.  
  2994.         case KEYCODE_PGDN:
  2995.             DBGMEM[which].base = (DBGMEM[which].base + DBGMEM[which].size) & AMASK;
  2996.             update_window = 1;
  2997.             break;
  2998.  
  2999.         case KEYCODE_HOME:
  3000.             DBGMEM[which].offset = 0;
  3001.             DBGMEM[which].base = 0x00000000;
  3002.             update_window = 1;
  3003.             break;
  3004.  
  3005.         case KEYCODE_END:
  3006.             DBGMEM[which].offset = DBGMEM[which].size - 1;
  3007.             DBGMEM[which].base = (0xffffffff - DBGMEM[which].offset) & AMASK;
  3008.             update_window = 1;
  3009.             break;
  3010.  
  3011.         case KEYCODE_H:
  3012.             DBGMEM[which].ascii = (DBGMEM[which].ascii + 1) % 3;
  3013.             update_window = 1;
  3014.             break;
  3015.  
  3016.  
  3017.         case KEYCODE_M:
  3018.             DBGMEM[which].mode = ++(DBGMEM[which].mode) % 3;
  3019.             /* Reset cursor coordinates and sizes of the edit info */
  3020.             memset( DBGMEM[which].edit, 0, sizeof(DBGMEM[which].edit) );
  3021.             update_window = 1;
  3022.             break;
  3023.  
  3024.         case KEYCODE_ENTER:
  3025.             DBG.window = EDIT_CMDS;
  3026.             break;
  3027.  
  3028.         default:
  3029.             cmd_default( i );
  3030.             update_window = 1;
  3031.     }
  3032.  
  3033.     if( update_window )
  3034.     {
  3035.         memcpy( DBGMEM[which].backup, DBGMEM[which].newval, DBGMEM[which].size );
  3036.         dump_mem( which, 0 );
  3037.     }
  3038. }
  3039.  
  3040. /**************************************************************************
  3041.  * edit_cmds_info
  3042.  * Search the cmdline for the beginning of a known command and
  3043.  * display some information in the caption of the command line input
  3044.  **************************************************************************/
  3045. static int edit_cmds_info( void )
  3046. {
  3047.     char *cmd = CMD;
  3048.     char hist_info[31+1];
  3049.     int i, l;
  3050.  
  3051.     hist_info[0] = '\0';
  3052.     if( DBG.hist_cnt )
  3053.         sprintf( hist_info, "\tHistory: %d", DBG.hist_cnt);
  3054.  
  3055.     if( strlen(cmd) )
  3056.     {
  3057.         for( i = 0; commands[i].name; i++ )
  3058.         {
  3059.             l = strlen(cmd);
  3060.             if( strlen(commands[i].name) < l )
  3061.                 l = strlen(commands[i].name);
  3062.             if( strncmp( cmd, commands[i].name, l ) == 0 && !isalnum(cmd[l]) )
  3063.             {
  3064.                 win_set_title( WIN_CMDS(activecpu), "Command: %s %s%s",
  3065.                     commands[i].name, commands[i].args, hist_info );
  3066.                 return i;
  3067.             }
  3068.             if( commands[i].alias )
  3069.             {
  3070.                 l = strlen(cmd);
  3071.                 if( strlen(commands[i].alias) < l )
  3072.                     l = strlen(commands[i].alias);
  3073.                 if( strncmp( cmd, commands[i].alias, l ) == 0 && !isalnum(cmd[l]) )
  3074.                 {
  3075.                     win_set_title( WIN_CMDS(activecpu), "Command: %s %s (aka %s)%s",
  3076.                         commands[i].alias, commands[i].args, commands[i].name, hist_info );
  3077.                     return i;
  3078.                 }
  3079.             }
  3080.         }
  3081.     }
  3082.     if( dbg_info_once )
  3083.     {
  3084.         win_set_title( WIN_CMDS(activecpu), "%s%s", dbg_info_once, hist_info );
  3085.         dbg_info_once = NULL;
  3086.     }
  3087.     else
  3088.     {
  3089.         win_set_title( WIN_CMDS(activecpu), "Command (press F1 for help)%s", hist_info );
  3090.     }
  3091.     return INVALID;
  3092. }
  3093.  
  3094. /**************************************************************************
  3095.  * edit_cmds_parse
  3096.  * Search the cmdline for a known command and if found,
  3097.  * strip it from cmdline and return it's index
  3098.  **************************************************************************/
  3099. static int edit_cmds_parse( char *cmdline )
  3100. {
  3101.     int i, l;
  3102.  
  3103.     for( i = 0; commands[i].valid; i++ )
  3104.     {
  3105.         if( !commands[i].name )
  3106.             continue;
  3107.         l = strlen( commands[i].name );
  3108.         if( !strncmp( cmdline, commands[i].name, l ) && !isalnum( cmdline[l] ) )
  3109.         {
  3110.             while( cmdline[l] && isspace( cmdline[l] ) ) l++;
  3111.             strcpy( cmdline, cmdline + l );
  3112.             return i;
  3113.         }
  3114.         if( commands[i].alias )
  3115.         {
  3116.             l = strlen( commands[i].alias );
  3117.             if( !strncmp( cmdline, commands[i].alias, l ) && !isalnum( cmdline[l] ) )
  3118.             {
  3119.                 while( cmdline[l] && isspace( cmdline[l] ) ) l++;
  3120.                 strcpy( cmdline, cmdline + l );
  3121.                 return i;
  3122.             }
  3123.         }
  3124.     }
  3125.     return INVALID;
  3126. }
  3127.  
  3128.  
  3129. /**************************************************************************
  3130.  * edit_cmds_append
  3131.  * Append a character (string) to the command line
  3132.  **************************************************************************/
  3133. static void edit_cmds_append( const char *src )
  3134. {
  3135.     char *cmdline = DBG.cmdline;
  3136.     UINT32 win = WIN_CMDS(activecpu);
  3137.     if( strlen(cmdline) < 80 )
  3138.     {
  3139.         strcat(cmdline, src);
  3140.         win_printf( win, "%s", src );
  3141.     }
  3142. }
  3143.  
  3144. void edit_cmds_reset( void )
  3145. {
  3146.     unsigned win = WIN_CMDS(activecpu);
  3147.     DBG.cmdline[0] = '\0';
  3148.     win_set_color( win, cur_col[E_CMDS] );
  3149.     win_set_curpos( win, 0, 0 );
  3150.     osd_set_screen_curpos( win_get_cx_abs(win), win_get_cy_abs(win) );
  3151.     win_erase_eol( win, ' ' );
  3152. }
  3153.  
  3154. /**************************************************************************
  3155.  * edit_cmds
  3156.  * Edit the command line input
  3157.  **************************************************************************/
  3158. static void edit_cmds(void)
  3159. {
  3160.     char *cmdline = DBG.cmdline;
  3161.     UINT32 win = WIN_CMDS(activecpu);
  3162.     const char *k;
  3163.     int i, l, cmd;
  3164.  
  3165.     osd_set_screen_curpos( win_get_cx_abs(win), win_get_cy_abs(win) );
  3166.  
  3167.     cmd = edit_cmds_info();
  3168.  
  3169.     i = keyboard_read_sync();
  3170.     k = keyboard_name(i);
  3171.     l = strlen(k);
  3172.  
  3173.     if( l == 1 )
  3174.         edit_cmds_append(k);
  3175.  
  3176.     switch( i )
  3177.     {
  3178.         case KEYCODE_SPACE:
  3179.             /*
  3180.              * Command completion for convenience:
  3181.              * found a valid command and no space in the command line yet?
  3182.              */
  3183.             if( cmd != INVALID && strchr(CMD, ' ') == NULL )
  3184.             {
  3185.                 strcpy( CMD, commands[cmd].name );
  3186.                 win_set_curpos( win, 0, 0 );
  3187.                 win_printf( win, "%s", CMD );
  3188.             }
  3189.             edit_cmds_append(" ");
  3190.             break;
  3191.  
  3192.         case KEYCODE_BACKSPACE:
  3193.             if( strlen(cmdline) > 0 )
  3194.             {
  3195.                 cmdline[strlen(cmdline)-1] = '\0';
  3196.                 win_printf( win, "\b \b" );
  3197.             }
  3198.             break;
  3199.  
  3200.         case KEYCODE_ENTER:
  3201.             if( strlen(cmdline) )
  3202.             {
  3203.                 cmd = edit_cmds_parse( cmdline );
  3204.                 if( cmd != INVALID && commands[cmd].function )
  3205.                     (*commands[cmd].function)();
  3206.                 break;
  3207.             }
  3208.             else
  3209.             {
  3210.                 /* ENTER in an empty line: do single step... */
  3211.                 i = KEYCODE_F8;
  3212.             }
  3213.             /* fall through */
  3214.         default:
  3215.             cmd_default( i );
  3216.     }
  3217. }
  3218.  
  3219. /**************************************************************************
  3220.  **************************************************************************
  3221.  *
  3222.  *        Command functions
  3223.  *
  3224.  **************************************************************************
  3225.  **************************************************************************/
  3226.  
  3227. /**************************************************************************
  3228.  * cmd_help
  3229.  * Display a help window containing a list of the (currently)
  3230.  * available commands and keystrokes.
  3231.  **************************************************************************/
  3232. static void cmd_help( void )
  3233. {
  3234.     UINT32 win = WIN_HELP;
  3235.     const char *title = "";
  3236.     char *help = malloc(4096+1), *dst;
  3237.     const char *src;
  3238.     unsigned w, h;
  3239.     int cmd = INVALID;
  3240.     int i, k, l, top, lines;
  3241.  
  3242.     if( !help )
  3243.     {
  3244.         win_msgbox( cur_col[E_ERROR],
  3245.             "Memory problem!", "Couldn't allocate help text buffer" );
  3246.         return;
  3247.     }
  3248.     dst = help;
  3249.  
  3250.     /* Decide what to print in the first lines of the help window */
  3251.     switch( DBG.window )
  3252.     {
  3253.     case EDIT_CMDS:
  3254.         title = "MAME Debugger command help";
  3255.         cmd = edit_cmds_info();
  3256.         /* Did not find the start of a command? */
  3257.         if( cmd == INVALID )
  3258.         {
  3259.             dst += sprintf( dst, "Welcome to the new MAME debugger V0.53!") + 1;
  3260.             dst += sprintf( dst, " " ) + 1;
  3261.             dst += sprintf( dst, "Many commands accept either a value or a register name.") + 1;
  3262.             dst += sprintf( dst, "You can indeed type either \"R HL = SP\" or \"R HL = 1FD0\".") + 1;
  3263.             dst += sprintf( dst, "In the syntax, where you see <address> you may generally") + 1;
  3264.             dst += sprintf( dst, "use a number or a register name of the active CPU.") + 1;
  3265.             dst += sprintf( dst, "A <boolean> can be specified as ON/OFF, YES/NO, Y/N or 1/0.") + 1;
  3266.             dst += sprintf( dst, "Note: You may put your preferences into a file \"mamedbg.cfg\" in your") + 1;
  3267.             dst += sprintf( dst, "main directory. Furthermore you can put game specific settings into a") + 1;
  3268.             dst += sprintf( dst, "set of files <driver>.cf<cpu>, eg. \"dkong.cf0\" and \"dkong.cf1\".") + 1;
  3269.             dst += sprintf( dst, "The files can contain different settings for the CPUs of a game.") + 1;
  3270.         }
  3271.         else
  3272.         {
  3273.             if( commands[cmd].alias )
  3274.                 dst += sprintf( dst, "%s %s (aka %s)", commands[cmd].name, commands[cmd].args, commands[cmd].alias ) + 1;
  3275.             else
  3276.                 dst += sprintf( dst, "%s %s", commands[cmd].name, commands[cmd].args ) + 1;
  3277.             src = commands[cmd].info;
  3278.             while( *src )
  3279.             {
  3280.                 *dst++ = (*src == '\n') ? '\0' : *src;
  3281.                 src++;
  3282.             }
  3283.             *dst++ = '\0';
  3284.         }
  3285.         break;
  3286.     case EDIT_REGS:
  3287.         title = "MAME debugger CPU registers help";
  3288.         dst += sprintf( dst, "%s [%s] Version %s", cpu_name(), cpu_core_family(), cpu_core_version() ) + 1;
  3289.         dst += sprintf( dst, "Address bits   : %d [%08X]", cpu_address_bits(), cpu_address_mask() ) + 1;
  3290.         dst += sprintf( dst, "Code align unit: %d byte(s)", cpu_align_unit() ) + 1;
  3291.         dst += sprintf( dst, "This CPU is    : %s endian", (ENDIAN == CPU_IS_LE) ? "little" : "big") + 1;
  3292.         dst += sprintf( dst, "Source file    : %s", cpu_core_file() ) + 1;
  3293.         dst += sprintf( dst, "%s", cpu_core_credits() ) + 1;
  3294.         break;
  3295.     case EDIT_DASM:
  3296.         title = "MAME debugger disassembly help";
  3297.         dst += sprintf( dst, "%s [%s]", cpu_name(), cpu_core_family() ) + 1;
  3298.         break;
  3299.     case EDIT_MEM1:
  3300.     case EDIT_MEM2:
  3301.         title = "MAME debugger memory editor help";
  3302.         dst += sprintf( dst, "You can move around using the cursor key block.") + 1;
  3303.         dst += sprintf( dst, "Change memory by keying in hex digits (0-9, A-F).") + 1;
  3304.         break;
  3305.     }
  3306.     dst += sprintf( dst, " " ) + 1;
  3307.     dst += sprintf( dst, "Valid commands and keys are:" ) + 1;
  3308.  
  3309.     for( i = 0; commands[i].valid; i++ )
  3310.     {
  3311.         if( commands[i].valid & ( 1 << DBG.window ) )
  3312.         {
  3313.             /* Already displayed this help? */
  3314.             if( i == cmd )
  3315.                 continue;
  3316.             dst += sprintf( dst, " " ) + 1;
  3317.             if( commands[i].name )
  3318.             {
  3319.                 if( commands[i].alias )
  3320.                     dst += sprintf( dst, "%s %s (aka %s)", commands[i].name, commands[i].args, commands[i].alias ) + 1;
  3321.                 else
  3322.                     dst += sprintf( dst, "%s %s", commands[i].name, commands[i].args ) + 1;
  3323.                 src = commands[i].info;
  3324.                 while( *src )
  3325.                 {
  3326.                     if( *src == '\n' )
  3327.                     {
  3328.                         if( src[1] != '\0' )
  3329.                             *dst++ = '\0';
  3330.                     }
  3331.                     else
  3332.                         *dst++ = *src;
  3333.                     src++;
  3334.                 }
  3335.                 *dst++ = '\0';
  3336.             }
  3337.             else
  3338.             {
  3339.                 dst += sprintf( dst, "[%s]\t%s", keyboard_name(commands[i].key), commands[i].info ) + 1;
  3340.             }
  3341.         }
  3342.     }
  3343.  
  3344.     /* Terminate *help with a second NULL byte */
  3345.     *dst++ = '\0';
  3346.  
  3347.     /* Count lines */
  3348.     for( lines = 0, src = help; *src && i > 0; src += strlen(src) + 1 )
  3349.         lines++;
  3350.  
  3351.     osd_get_screen_size( &w, &h );
  3352.     win_create( win, 0,
  3353.         2,1,w-2-4,h-2-3, cur_col[E_HELP], cur_col[E_FRAME], ' ',
  3354.         BORDER_TOP | BORDER_LEFT | BORDER_RIGHT | BORDER_BOTTOM | SHADOW );
  3355.     win_set_title( win, title );
  3356.     win_show( win );
  3357.     h = win_get_h( win );
  3358.  
  3359.     top = 0;
  3360.     do
  3361.     {
  3362.         for( src = help, i = top; *src && i > 0; src += strlen(src) + 1 )
  3363.             i--;
  3364.         win_set_curpos( win, 0, 0 );
  3365.         l = 0;
  3366.         do
  3367.         {
  3368.             if( *src )
  3369.             {
  3370.                 win_printf( win, src );
  3371.                 src += strlen(src) + 1;
  3372.             }
  3373.             win_erase_eol( win, ' ' );
  3374.             win_putc( win, '\n');
  3375.             l++;
  3376.         } while( l < win_get_h(win) );
  3377.  
  3378.         k = keyboard_read_sync();
  3379.         switch( k )
  3380.         {
  3381.             case KEYCODE_UP:
  3382.                 if( top > 0 )
  3383.                     top--;
  3384.                 k = KEYCODE_NONE;
  3385.                 break;
  3386.             case KEYCODE_ENTER:
  3387.             case KEYCODE_DOWN:
  3388.                 if( top < lines - h )
  3389.                     top++;
  3390.                 k = KEYCODE_NONE;
  3391.                 break;
  3392.             case KEYCODE_PGUP:
  3393.                 if( top - h > 0 )
  3394.                     top -= h;
  3395.                 else
  3396.                     top = 0;
  3397.                 k = KEYCODE_NONE;
  3398.                 break;
  3399.             case KEYCODE_PGDN:
  3400.                 if( top + h < lines - h )
  3401.                     top += h;
  3402.                 else
  3403.                     top = lines - h;
  3404.                 k = KEYCODE_NONE;
  3405.                 break;
  3406.         }
  3407.     } while( k == KEYCODE_NONE );
  3408.  
  3409.     free( help );
  3410.  
  3411.     win_close( win );
  3412. }
  3413.  
  3414. /**************************************************************************
  3415.  * cmd_default
  3416.  * Handle a key stroke with no special meaning inside the active window
  3417.  **************************************************************************/
  3418. static void cmd_default( int code )
  3419. {
  3420.     int i;
  3421.     for( i = 0; commands[i].valid; i++ )
  3422.     {
  3423.         if( (commands[i].valid & (1<<DBG.window)) && commands[i].key == code )
  3424.         {
  3425.             if( commands[i].function )
  3426.                 (*commands[i].function)();
  3427.             return;
  3428.         }
  3429.     }
  3430. }
  3431.  
  3432.  
  3433. /**************************************************************************
  3434.  * cmd_set_element_color
  3435.  * Set a specific color foreground and background
  3436.  **************************************************************************/
  3437. static void cmd_set_element_color( void )
  3438. {
  3439.     char *cmd = CMD;
  3440.     unsigned element, fg, bg, win;
  3441.     int length;
  3442.  
  3443.     element = get_option_or_value( &cmd, &length, ELEMENT_NAMES );
  3444.     if( length )
  3445.     {
  3446.         fg = get_option_or_value( &cmd, &length, COLOR_NAMES );
  3447.         if( length )
  3448.         {
  3449.             bg = get_option_or_value( &cmd, &length, COLOR_NAMES );
  3450.             if( !length ) bg = 0;    /* BLACK is default background */
  3451.         }
  3452.         else
  3453.         {
  3454.             bg = def_col[element] >> 4;
  3455.             fg = def_col[element] & 15;
  3456.         }
  3457.         cur_col[element] = fg + 16 * bg;
  3458.         switch( element )
  3459.         {
  3460.             case E_TITLE:
  3461.                 for( win = 0; win < MAX_WINDOWS; win++ )
  3462.                     win_set_title_color( win, cur_col[element] );
  3463.                 break;
  3464.             case E_FRAME:
  3465.                 for( win = 0; win < MAX_WINDOWS; win++ )
  3466.                     win_set_frame_color( win, cur_col[element] );
  3467.                 break;
  3468.         }
  3469.     }
  3470.     else
  3471.     {
  3472.         memcpy( cur_col, def_col, sizeof(cur_col) );
  3473.         for( win = 0; win < MAX_WINDOWS; win++ )
  3474.             win_set_title_color( win, cur_col[E_TITLE] );
  3475.         for( win = 0; win < MAX_WINDOWS; win++ )
  3476.             win_set_frame_color( win, cur_col[E_FRAME] );
  3477.     }
  3478.  
  3479.     edit_cmds_reset();
  3480.     dbg_update = 1;
  3481. }
  3482.  
  3483. /**************************************************************************
  3484.  * cmd_set_screen_size
  3485.  * Set new screen size width and height
  3486.  **************************************************************************/
  3487. static void cmd_set_screen_size( void )
  3488. {
  3489.     char *cmd = CMD;
  3490.     unsigned w, h, new_w, new_h;
  3491.     int length;
  3492.  
  3493.     osd_get_screen_size( &w, &h );
  3494.  
  3495.     new_w = dtou( &cmd, &length );
  3496.     if( length )
  3497.     {
  3498.         new_h = dtou( &cmd, &length );
  3499.         if( !length ) new_h = h;
  3500.     }
  3501.     else
  3502.     {
  3503.         new_w = 80;
  3504.         new_h = 25;
  3505.     }
  3506.     if( new_w < 80 ) new_w = 80;
  3507.     if( new_h < 25 ) new_h = 25;
  3508.  
  3509.     dbg_close_windows();
  3510.     osd_set_screen_size( new_w, new_h );
  3511.     dbg_open_windows();
  3512.  
  3513.     edit_cmds_reset();
  3514.     dbg_update = 1;
  3515. }
  3516.  
  3517. /**************************************************************************
  3518.  * cmd_brk_regs_set
  3519.  * Set the register breakpoint for the current CPU
  3520.  **************************************************************************/
  3521. static void cmd_brk_regs_set( void )
  3522. {
  3523.     char *cmd = CMD;
  3524.     unsigned data;
  3525.     int length;
  3526.  
  3527.     DBG.brk_regs = get_register_id( &cmd, &length );
  3528.     if( DBG.brk_regs != INVALID )
  3529.     {
  3530.         DBG.brk_regs_oldval = cpu_get_reg(DBG.brk_regs);
  3531.         data = get_register_or_value( &cmd, &length );
  3532.         if( length )
  3533.         {
  3534.             DBG.brk_regs_newval = data;
  3535.             data = get_register_or_value( &cmd, &length );
  3536.             if( length )
  3537.             {
  3538.                 DBG.brk_regs_mask = data;
  3539.                 /* Remove masked bits from the new value too ;-) */
  3540.                 DBG.brk_regs_newval &= data;
  3541.             }
  3542.             else
  3543.             {
  3544.                 DBG.brk_regs_mask = 0xffffffff;
  3545.             }
  3546.         }
  3547.         else
  3548.         {
  3549.             DBG.brk_regs_newval = INVALID;
  3550.             DBG.brk_regs_mask = 0xffffffff;
  3551.         }
  3552.     }
  3553.     dbg_update = 1;
  3554.     edit_cmds_reset();
  3555. }
  3556.  
  3557. /**************************************************************************
  3558.  * cmd_brk_regs_clear
  3559.  * Reset the watchpoint for the current CPU to INVALID
  3560.  **************************************************************************/
  3561. static void cmd_brk_regs_clear( void )
  3562. {
  3563.     if( DBG.brk_regs != INVALID )
  3564.     {
  3565.         DBG.brk_regs = INVALID;
  3566.         DBG.brk_regs_oldval = INVALID;
  3567.         DBG.brk_regs_newval = INVALID;
  3568.         DBG.brk_regs_mask = 0xffffffff;
  3569.         dbg_update = 1;
  3570.     }
  3571.     edit_cmds_reset();
  3572. }
  3573.  
  3574. /**************************************************************************
  3575.  * cmd_brk_data_set
  3576.  * Set the watchpoint for the current CPU to the specified address
  3577.  * The monitored data is one byte at the given address
  3578.  **************************************************************************/
  3579. static void cmd_brk_data_set( void )
  3580. {
  3581.     char *cmd = CMD;
  3582.     unsigned data;
  3583.     int length;
  3584.  
  3585.     DBG.brk_data = get_register_or_value( &cmd, &length );
  3586.  
  3587.     DBG.brk_data = rshift(DBG.brk_data) & AMASK; /* EHC 11/14/99: Need to shift + mask otherwise we die */
  3588.  
  3589.     if( length )
  3590.     {
  3591.         data = RDMEM(DBG.brk_data);
  3592.  
  3593.         DBG.brk_data_oldval = data;
  3594.         data = get_register_or_value( &cmd, &length );
  3595.  
  3596.         if( length )
  3597.         {
  3598.             DBG.brk_data_newval = data;
  3599.         }
  3600.         else
  3601.         {
  3602.             DBG.brk_data_newval = INVALID;
  3603.         }
  3604.     }
  3605.  
  3606.     dbg_update = 1;
  3607.     edit_cmds_reset();
  3608. }
  3609.  
  3610. /**************************************************************************
  3611.  * cmd_brk_data_clear
  3612.  * Reset the watchpoint for the current CPU to INVALID
  3613.  **************************************************************************/
  3614. static void cmd_brk_data_clear( void )
  3615. {
  3616.     if( DBG.brk_data != INVALID )
  3617.     {
  3618.         DBG.brk_data = INVALID;
  3619.         DBG.brk_data_oldval = INVALID;
  3620.         DBG.brk_data_newval = INVALID;
  3621.         dbg_update = 1;
  3622.     }
  3623.     edit_cmds_reset();
  3624. }
  3625.  
  3626. /**************************************************************************
  3627.  * cmd_brk_exec_set
  3628.  * Set the execution breakpoint for the current CPU to the specified address
  3629.  **************************************************************************/
  3630. static void cmd_brk_exec_set( void )
  3631. {
  3632.     char *cmd = CMD;
  3633.     unsigned times;
  3634.     int length;
  3635.  
  3636.     DBG.brk_exec = get_register_or_value( &cmd, &length );
  3637.     if( length )
  3638.     {
  3639.         times = get_register_or_value( &cmd, &length );
  3640.         if( length )
  3641.         {
  3642.             DBG.brk_exec_times = times;
  3643.             DBG.brk_exec_reset = times;
  3644.         }
  3645.         else
  3646.         {
  3647.             DBG.brk_exec_times = 0;
  3648.             DBG.brk_exec_reset = 0;
  3649.         }
  3650.     }
  3651.     else
  3652.     {
  3653.         DBG.brk_exec = DBGDASM.pc_cur;
  3654.         DBG.brk_exec_times = 0;
  3655.         DBG.brk_exec_reset = 0;
  3656.     }
  3657.     dbg_update = 1;
  3658.     edit_cmds_reset();
  3659. }
  3660.  
  3661. /**************************************************************************
  3662.  * cmd_brk_exec_clear
  3663.  * Reset the execution breakpoint for the current CPU to INVALID
  3664.  **************************************************************************/
  3665. static void cmd_brk_exec_clear( void )
  3666. {
  3667.     if( DBG.brk_exec != INVALID )
  3668.     {
  3669.         DBG.brk_exec = INVALID;
  3670.         DBG.brk_exec_times = 0;
  3671.         DBG.brk_exec_reset = 0;
  3672.         dbg_update = 1;
  3673.     }
  3674.     edit_cmds_reset();
  3675. }
  3676.  
  3677. /**************************************************************************
  3678.  * cmd_display_memory
  3679.  * Set one of the memory display window's start address
  3680.  **************************************************************************/
  3681. static void cmd_display_memory( void )
  3682. {
  3683.     char *cmd = CMD;
  3684.     unsigned which, address;
  3685.     int length;
  3686.  
  3687.     which = xtou( &cmd, &length );
  3688.     if( length )
  3689.     {
  3690.         address = get_register_or_value( &cmd, &length );
  3691.         if( length )
  3692.         {
  3693.             which = (which - 1) % MAX_MEM;
  3694.         }
  3695.         else
  3696.         {
  3697.             address = which;
  3698.             which = 0;
  3699.         }
  3700.         address = rshift(address) & AMASK;
  3701.         DBGMEM[which].base = address;
  3702.         dump_mem( which, 1 );
  3703.     }
  3704.     edit_cmds_reset();
  3705. }
  3706.  
  3707. /**************************************************************************
  3708.  * cmd_dasm_to_file
  3709.  * Disassemble a range of code and output it to a file
  3710.  **************************************************************************/
  3711. static void cmd_dasm_to_file( void )
  3712. {
  3713.     char buffer[127+1], *cmd = CMD;
  3714.     const char *filename;
  3715.     int length;
  3716.     FILE *file;
  3717.     unsigned i, pc, size, start, end, width, opcodes;
  3718.  
  3719.     filename = get_file_name( &cmd, &length );
  3720.     if( !length )
  3721.     {
  3722.         win_msgbox( cur_col[E_ERROR], "DASM arguments",
  3723.             "Filename missing");
  3724.         edit_cmds_reset();
  3725.         return;
  3726.     }
  3727.     start = get_register_or_value( &cmd, &length );
  3728.     if( !length )
  3729.     {
  3730.         win_msgbox( cur_col[E_ERROR], "DASM arguments",
  3731.             "Start address missing");
  3732.         edit_cmds_reset();
  3733.         return;
  3734.     }
  3735.     end = get_register_or_value( &cmd, &length );
  3736.     if( !length )
  3737.     {
  3738.         win_msgbox( cur_col[E_ERROR], "DASM arguments",
  3739.             "End address missing");
  3740.         edit_cmds_reset();
  3741.         return;
  3742.     }
  3743.     opcodes = get_boolean( &cmd, &length );
  3744.     if( !length ) opcodes = 1;    /* default to display opcodes */
  3745.  
  3746.     file = fopen(filename, "w");
  3747.     if( !file )
  3748.     {
  3749.         win_msgbox( cur_col[E_ERROR], "DASM to file",
  3750.             "Could not create %s", filename);
  3751.         edit_cmds_reset();
  3752.         return;
  3753.     }
  3754.  
  3755.     width = (ABITS + ASHIFT + 3) / 4;
  3756.  
  3757.     for( pc = start; pc <= end; /* */ )
  3758.     {
  3759.         unsigned p = rshift(pc);
  3760.         unsigned s;
  3761.         size = cpu_dasm( buffer, pc );
  3762.         s = rshift(size);
  3763.  
  3764.         fprintf(file, "%0*X: ", width, pc );
  3765.         switch( ALIGN )
  3766.         {
  3767.         case 1: /* dump bytes */
  3768.             for( i = 0; i < INSTL; i++ )
  3769.             {
  3770.                 if ( i < s )
  3771.                     fprintf( file, "%02X ",
  3772.                         RDMEM(order(p+i,1)) );
  3773.                 else
  3774.                     fprintf( file, "   ");
  3775.             }
  3776.             break;
  3777.         case 2: /* dump words */
  3778.             for( i = 0; i < INSTL; i += 2 )
  3779.             {
  3780.                 if ( i < s )
  3781.                     fprintf( file, "%02X%02X ",
  3782.                         RDMEM(order(p+i+0,2)), RDMEM(order(p+i+1,2)) );
  3783.                 else
  3784.                     fprintf( file, "     ");
  3785.             }
  3786.             break;
  3787.         case 4: /* dump dwords */
  3788.             for( i = 0; i < INSTL; i += 4 )
  3789.             {
  3790.                 if ( i < s )
  3791.                     fprintf( file, "%02X%02X%02X%02X ",
  3792.                         RDMEM(order(p+i+0,4)), RDMEM(order(p+i+1,4)),
  3793.                         RDMEM(order(p+i+2,4)), RDMEM(order(p+i+3,4)) );
  3794.                 else
  3795.                     fprintf( file, "     ");
  3796.             }
  3797.             break;
  3798.         }
  3799.         fprintf( file, "%s\n", buffer );
  3800.         if( (pc + size) < pc )
  3801.             break;
  3802.         pc += size;
  3803.     }
  3804.     fclose( file );
  3805.  
  3806.     edit_cmds_reset();
  3807. }
  3808.  
  3809. /**************************************************************************
  3810.  * cmd_dump_to_file
  3811.  * (Hex-)Dump a range of code and output it to a file
  3812.  **************************************************************************/
  3813. static void cmd_dump_to_file( void )
  3814. {
  3815.     UINT8 buffer[16];
  3816.     char *cmd = CMD;
  3817.     const char *filename;
  3818.     int length;
  3819.     FILE *file;
  3820.     unsigned x, offs, address = 0, start, end, width, data;
  3821.     unsigned datasize, asciimode;
  3822.  
  3823.     filename = get_file_name( &cmd, &length );
  3824.     if( !length )
  3825.     {
  3826.         win_msgbox( cur_col[E_ERROR], "DUMP arguments",
  3827.             "<filename> missing");
  3828.         edit_cmds_reset();
  3829.         return;
  3830.     }
  3831.     start = get_register_or_value( &cmd, &length );
  3832.     if( !length )
  3833.     {
  3834.         win_msgbox( cur_col[E_ERROR], "DUMP arguments",
  3835.             "<start> address missing");
  3836.         edit_cmds_reset();
  3837.         return;
  3838.     }
  3839.     start = rshift(start);
  3840.     end = get_register_or_value( &cmd, &length );
  3841.     if( !length )
  3842.     {
  3843.         win_msgbox( cur_col[E_ERROR], "DUMP arguments",
  3844.             "<end> address missing");
  3845.         edit_cmds_reset();
  3846.         return;
  3847.     }
  3848.     end = rshift(end);
  3849.     asciimode = 1;        /* default to translation table */
  3850.     datasize = ALIGN*2;    /* default to align unit of that CPU */
  3851.     data = get_option_or_value( &cmd, &length, "BYTE\0WORD\0DWORD\0");
  3852.     if( length )
  3853.     {
  3854.         if( data != 1 && data != 2 && data != 4 )
  3855.         {
  3856.             win_msgbox( cur_col[E_ERROR], "DUMP arguments",
  3857.                 "Wrong <data size>. Only BYTE, WORD or DWORD\n(also 0, 1 or 2) are supported");
  3858.             data = 1;
  3859.         }
  3860.         datasize = data << 1;
  3861.         /* look if there's also an ASCII mode specified */
  3862.         data = get_option_or_value( &cmd, &length, "OFF\0TRANSLATE\0FULL\0" );
  3863.         if( length )
  3864.         {
  3865.             if( data > 2 )
  3866.             {
  3867.                 win_msgbox( cur_col[E_ERROR], "DUMP arguments",
  3868.                     "Wrong ASCII mode. Only OFF, TRANSLATE or FULL\n(also 0,1 or 2) are supported");
  3869.                 data = 1;
  3870.             }
  3871.             asciimode = data;
  3872.         }
  3873.     }
  3874.  
  3875.     file = fopen(filename, "w");
  3876.     if( !file )
  3877.     {
  3878.         win_msgbox( cur_col[E_ERROR], "DUMP to file",
  3879.             "Could not create %s", filename);
  3880.         edit_cmds_reset();
  3881.         return;
  3882.     }
  3883.  
  3884.     width = (ABITS + ASHIFT + 3) / 4;
  3885.  
  3886.     for( x = 0, offs = 0; offs + start <= end; offs++ )
  3887.     {
  3888.         switch( datasize )
  3889.         {
  3890.             case 2:
  3891.                 address = (start + order(offs,1)) & AMASK;
  3892.                 break;
  3893.             case 4:
  3894.                 address = (start + order(offs,2)) & AMASK;
  3895.                 break;
  3896.             case 8:
  3897.                 address = (start + order(offs,4)) & AMASK;
  3898.                 break;
  3899.         }
  3900.         buffer[offs & 15] = RDMEM( address );
  3901.         if( (offs & 15) == 0 )
  3902.             fprintf(file, "%0*X: ", width, lshift((start + offs) & AMASK) );
  3903.         fprintf(file, "%02X", buffer[offs & 15] );
  3904.         if( (offs & 15) == 15 )
  3905.         {
  3906.             unsigned o;
  3907.             if( asciimode )
  3908.             {
  3909.                 fputc( ' ', file );
  3910.                 if( asciimode == 1 )
  3911.                     for( o = 0; o < 16; o++ )
  3912.                         fputc( trans_table[buffer[o]], file );
  3913.                 else
  3914.                     for( o = offs - 15; o <= offs; o++ )
  3915.                         fputc( (buffer[o] < 32) ? '.' : buffer[o], file );
  3916.             }
  3917.             fprintf(file, "\n" );
  3918.             x = 0;
  3919.         }
  3920.         else
  3921.         if( (x += 2) == datasize )
  3922.         {
  3923.             if( (offs & 15) == 7 )
  3924.                 fprintf(file, "-");
  3925.             else
  3926.                 fprintf(file, " ");
  3927.             x = 0;
  3928.         }
  3929.     }
  3930.     fclose( file );
  3931.  
  3932.     edit_cmds_reset();
  3933. }
  3934.  
  3935. /**************************************************************************
  3936.  * cmd_save_to_file
  3937.  * Save binary image of a range of OP_ROM or OP_RAM
  3938.  **************************************************************************/
  3939. static void cmd_save_to_file( void )
  3940. {
  3941.     char *cmd = CMD;
  3942.     const char *filename;
  3943.     int length;
  3944.     FILE *file;
  3945.     unsigned start, end;
  3946.     unsigned save_what;
  3947.  
  3948.     filename = get_file_name( &cmd, &length );
  3949.     if( !length )
  3950.     {
  3951.         win_msgbox( cur_col[E_ERROR], "SAVE arguments",
  3952.             "<filename> missing");
  3953.         edit_cmds_reset();
  3954.         return;
  3955.     }
  3956.     start = get_register_or_value( &cmd, &length );
  3957.     if( !length )
  3958.     {
  3959.         win_msgbox( cur_col[E_ERROR], "SAVE arguments",
  3960.             "<start> address missing");
  3961.         edit_cmds_reset();
  3962.         return;
  3963.     }
  3964.     end = get_register_or_value( &cmd, &length );
  3965.     if( !length )
  3966.     {
  3967.         win_msgbox( cur_col[E_ERROR], "SAVE arguments",
  3968.             "<end> address missing");
  3969.         edit_cmds_reset();
  3970.         return;
  3971.     }
  3972.  
  3973.     save_what = get_option_or_value( &cmd, &length, "OPCODES\0DATA\0");
  3974.     if( !length ) save_what = 0;    /* default to OP_ROM */
  3975.  
  3976.     file = fopen(filename, "wb");
  3977.     if( !file )
  3978.     {
  3979.         win_msgbox( cur_col[E_ERROR], "SAVE to file",
  3980.             "Could not create %s", filename);
  3981.         edit_cmds_reset();
  3982.         return;
  3983.     }
  3984.  
  3985.     if( save_what )
  3986.         fwrite( &OP_RAM[start], 1, end+1-start, file );
  3987.     else
  3988.         fwrite( &OP_ROM[start], 1, end+1-start, file );
  3989.  
  3990.     fclose( file );
  3991.  
  3992.     edit_cmds_reset();
  3993. }
  3994.  
  3995. /**************************************************************************
  3996.  * cmd_edit_memory
  3997.  * Set one of the memory display window's start address and
  3998.  * switch to that window
  3999.  **************************************************************************/
  4000. static void cmd_edit_memory( void )
  4001. {
  4002.     char *cmd = CMD;
  4003.     unsigned which, address;
  4004.     int length;
  4005.  
  4006.     which = xtou( &cmd, &length );
  4007.     if( length )
  4008.     {
  4009.         which = (which - 1) % MAX_MEM;
  4010.         address = get_register_or_value( &cmd, &length );
  4011.         address = rshift(address) & AMASK;
  4012.         if( length )
  4013.         {
  4014.             DBGMEM[which].offset = address % DBGMEM[which].size;
  4015.             DBGMEM[which].base = address - DBGMEM[which].offset;
  4016.             DBGMEM[which].nibble = 0;
  4017.             dump_mem( which, 0 );
  4018.         }
  4019.         switch( which )
  4020.         {
  4021.             case 0: DBG.window = EDIT_MEM1; break;
  4022.             case 1: DBG.window = EDIT_MEM2; break;
  4023.         }
  4024.     }
  4025.     edit_cmds_reset();
  4026. }
  4027.  
  4028. /**************************************************************************
  4029.  * cmd_search_memory
  4030.  * Search the memory for a sequence of bytes
  4031.  **************************************************************************/
  4032. static void cmd_search_memory(void)
  4033. {
  4034.     static UINT8 search_data[16];
  4035.     static int search_count = 0;
  4036.     UINT32 win = MAX_WINDOWS-3;
  4037.     unsigned which = (DBG.window == WIN_MEM1(activecpu)) ? 0 : 1;
  4038.     unsigned w, h;
  4039.     unsigned shift, mask, val;
  4040.     const char *k;
  4041.     int i, offset, nibble;
  4042.  
  4043.     osd_get_screen_size( &w, &h );
  4044.     win_create( win, 1, 2, 2, w-4, 2,
  4045.         cur_col[E_PROMPT], cur_col[E_FRAME], ' ',
  4046.         BORDER_TOP | BORDER_BOTTOM | BORDER_LEFT | BORDER_RIGHT );
  4047.     win_set_title( win, "Search byte(s) in memory");
  4048.     win_show( win );
  4049.  
  4050.     offset = 0;
  4051.     nibble = 0;
  4052.  
  4053.     do
  4054.     {
  4055.         win_set_curpos( win, 0, 0 );
  4056.         for( i = 0; i < search_count; i++ )
  4057.             win_printf( win, "%02X ", search_data[i] );
  4058.         win_erase_eol( win, ' ' );
  4059.         win_set_curpos( win, 0, 1 );
  4060.         for( i = 0; i < search_count; i++ )
  4061.             win_printf( win, "%c  ", search_data[i] < 32 ? '.' : search_data[i] );
  4062.         win_erase_eol( win, ' ' );
  4063.  
  4064.         win_set_curpos( win, offset * 3 + nibble, 0 );
  4065.         osd_set_screen_curpos( win_get_cx_abs(win), win_get_cy_abs(win) );
  4066.  
  4067.         i = keyboard_read_sync();
  4068.         k = keyboard_name(i);
  4069.  
  4070.         shift = (1 - nibble) * 4;
  4071.         mask = ~(0xf << shift);
  4072.  
  4073.         if( strlen(k) == 1 )
  4074.         {
  4075.             switch( k[0] )
  4076.             {
  4077.                 case '0': case '1': case '2': case '3':
  4078.                 case '4': case '5': case '6': case '7':
  4079.                 case '8': case '9': case 'A': case 'B':
  4080.                 case 'C': case 'D': case 'E': case 'F':
  4081.                     if( offset == 16 )
  4082.                         break;
  4083.                     if( offset == search_count )
  4084.                         search_count++;
  4085.                     val = k[0] - '0';
  4086.                     if( val > 9 ) val -= 7;
  4087.                     val <<= shift;
  4088.                     /* now modify the register */
  4089.                     search_data[offset] = (search_data[offset] & mask ) | val;
  4090.                     i = KEYCODE_RIGHT;    /* advance to next nibble */
  4091.                     break;
  4092.             }
  4093.         }
  4094.  
  4095.         switch( i )
  4096.         {
  4097.             case KEYCODE_DEL:
  4098.                 if( offset < search_count )
  4099.                 {
  4100.                     for( i = offset; i < 15; i++ )
  4101.                         search_data[i] = search_data[i+1];
  4102.                     search_count--;
  4103.                 }
  4104.                 break;
  4105.  
  4106.             case KEYCODE_INSERT:
  4107.                 if( search_count < 16 )
  4108.                 {
  4109.                     for( i = 15; i > offset; i-- )
  4110.                         search_data[i] = search_data[i-1];
  4111.                     search_data[offset] = 0;
  4112.                     search_count++;
  4113.                 }
  4114.                 break;
  4115.  
  4116.             case KEYCODE_BACKSPACE:
  4117.                 if( nibble > 0 || offset > 0 )
  4118.                 {
  4119.                     if( nibble > 0 )
  4120.                     {
  4121.                         nibble--;
  4122.                     }
  4123.                     else
  4124.                     if( offset > 0 )
  4125.                     {
  4126.                         offset--;
  4127.                         nibble = 1;
  4128.                     }
  4129.                     shift = (1 - nibble) * 4;
  4130.                     mask = ~(0xf << shift);
  4131.                     /* now modify the value */
  4132.                     search_data[offset] = search_data[offset] & mask;
  4133.                 }
  4134.                 break;
  4135.  
  4136.             case KEYCODE_LEFT:
  4137.                 if( nibble > 0 )
  4138.                 {
  4139.                     nibble--;
  4140.                 }
  4141.                 else
  4142.                 if( offset > 0 )
  4143.                 {
  4144.                     offset--;
  4145.                     nibble = 1;
  4146.                 }
  4147.                 break;
  4148.  
  4149.             case KEYCODE_RIGHT:
  4150.                 if( offset < search_count )
  4151.                 {
  4152.                     if( nibble < 1 )
  4153.                     {
  4154.                         nibble++;
  4155.                     }
  4156.                     else
  4157.                     {
  4158.                         offset++;
  4159.                         nibble = 0;
  4160.                     }
  4161.                 }
  4162.                 break;
  4163.  
  4164.             case KEYCODE_HOME:
  4165.                 offset = 0;
  4166.                 nibble = 0;
  4167.                 break;
  4168.  
  4169.             case KEYCODE_END:
  4170.                 offset = search_count;
  4171.                 nibble = 0;
  4172.                 break;
  4173.         }
  4174.     } while( i != KEYCODE_ENTER && i != KEYCODE_ESC );
  4175.  
  4176.     if( i == KEYCODE_ENTER && search_count > 0 )
  4177.     {
  4178.         static char dbg_info[32+1];
  4179.         unsigned addr, start;
  4180.  
  4181.         start = (DBGMEM[which].base + DBGMEM[which].offset) & AMASK;
  4182.  
  4183.         for( addr = start + 1; addr != start; addr = ++addr & AMASK )
  4184.         {
  4185.             if( (addr & (AMASK >> 8)) == 0 )
  4186.             {
  4187.                 win_set_title( win, "[%3.0f%%] %s/%s",
  4188.                     100.0 * addr / (AMASK + 1),
  4189.                     kilobyte(addr), kilobyte(AMASK + 1) );
  4190.                 osd_screen_update();
  4191.             }
  4192.             for( i = 0; i < search_count; i++)
  4193.                 if( RDMEM( addr+i ) != search_data[i] )
  4194.                     break;
  4195.             if( i == search_count )
  4196.             {
  4197.                 sprintf(dbg_info, "Found at address $%X", addr);
  4198.                 dbg_info_once = dbg_info;
  4199.                 DBGMEM[which].offset = addr % DBGMEM[which].size;
  4200.                 DBGMEM[which].base = addr - DBGMEM[which].offset;
  4201.                 win_close(win);
  4202.                 dbg_update = 1;
  4203.                 return;
  4204.             }
  4205.         }
  4206.         sprintf(dbg_info, "Not found");
  4207.         dbg_info_once = dbg_info;
  4208.     }
  4209.     win_close(win);
  4210. }
  4211.  
  4212. /**************************************************************************
  4213.  * cmd_fast
  4214.  * Hmm.. no idea ;)
  4215.  **************************************************************************/
  4216. static void cmd_fast( void )
  4217. {
  4218.     dbg_fast = 1;
  4219.     cmd_go_break();
  4220. }
  4221.  
  4222. /**************************************************************************
  4223.  * cmd_go_break
  4224.  * Let the emulation run and optionally set a breakpoint
  4225.  **************************************************************************/
  4226. static void cmd_go_break( void )
  4227. {
  4228.     char *cmd = CMD;
  4229.     unsigned brk;
  4230.     int length;
  4231.  
  4232.     brk = get_register_or_value( &cmd, &length );
  4233.     if( length )
  4234.         DBG.brk_temp = brk;
  4235.  
  4236.     dbg_update = 0;
  4237.     dbg_active = 0;
  4238.  
  4239.     osd_sound_enable(1);
  4240.     osd_set_display(
  4241.         Machine->scrbitmap->width,
  4242.         Machine->scrbitmap->height,
  4243.         Machine->drv->video_attributes);
  4244. }
  4245.  
  4246. /**************************************************************************
  4247.  * cmd_here
  4248.  * Set a temporary breakpoint at the cursor PC and let the emulation run
  4249.  **************************************************************************/
  4250. static void cmd_here( void )
  4251. {
  4252.     DBG.brk_temp = DBGDASM.pc_cur;
  4253.  
  4254.     dbg_update = 0;
  4255.     dbg_active = 0;
  4256.  
  4257.     osd_sound_enable(1);
  4258.     osd_set_display(Machine->scrbitmap->width,
  4259.                     Machine->scrbitmap->height,
  4260.                     Machine->drv->video_attributes);
  4261.  
  4262.     edit_cmds_reset();
  4263. }
  4264.  
  4265. /**************************************************************************
  4266.  * cmd_set_ignore
  4267.  * Ignore a CPU while debugging and tracing
  4268.  **************************************************************************/
  4269. static void cmd_set_ignore( void )
  4270. {
  4271.     char *cmd = CMD;
  4272.     unsigned cpunum;
  4273.     int i, length, already_ignored;
  4274.  
  4275.     cpunum = xtou( &cmd, &length );
  4276.     if( cpunum < totalcpu )
  4277.     {
  4278.         if( !dbg[cpunum].ignore )
  4279.         {
  4280.             for( i = 0, already_ignored = 0; i < totalcpu; i++ )
  4281.                 if(dbg[i].ignore) ++already_ignored;
  4282.             if( already_ignored + 1 >= totalcpu )
  4283.             {
  4284.                 win_msgbox( cur_col[E_ERROR], "Ignore CPU",
  4285.                     "No, I won't do that! ;-)\nIgnoring all CPUs is a bad idea.");
  4286.                 edit_cmds_reset();
  4287.                 return;
  4288.             }
  4289.             dbg[cpunum].ignore = 1;
  4290.             if( cpunum == activecpu )
  4291.                 cmd_focus_next_cpu();
  4292.         }
  4293.     }
  4294.     else
  4295.     {
  4296.         win_msgbox( cur_col[E_ERROR], "Ignore CPU",
  4297.             "The selected CPU# is too high.\nOnly %d CPUs (0..%d) are used", totalcpu, totalcpu-1);
  4298.     }
  4299.  
  4300.     edit_cmds_reset();
  4301. }
  4302.  
  4303. /**************************************************************************
  4304.  * cmd_set_observe
  4305.  * Observe a CPU while debugging and tracing
  4306.  **************************************************************************/
  4307. static void cmd_set_observe( void )
  4308. {
  4309.     char *cmd = CMD;
  4310.     unsigned cpunum;
  4311.     int length;
  4312.  
  4313.     cpunum = xtou( &cmd, &length );
  4314.     if( cpunum < totalcpu )
  4315.     {
  4316.         dbg[cpunum].ignore = 0;
  4317.     }
  4318.     else
  4319.     {
  4320.         win_msgbox( cur_col[E_ERROR], "Observe CPU",
  4321.             "The selected CPU# is too high.\nOnly %d CPUs (0..%d) are used", totalcpu, totalcpu-1);
  4322.     }
  4323.  
  4324.     edit_cmds_reset();
  4325. }
  4326.  
  4327. /**************************************************************************
  4328.  * cmd_jump
  4329.  * Jump to the specified address in the disassembly window
  4330.  **************************************************************************/
  4331. static void cmd_jump( void )
  4332. {
  4333.     char *cmd = CMD;
  4334.     unsigned address;
  4335.     int length;
  4336.  
  4337.     address = get_register_or_value( &cmd, &length );
  4338.     if( length > 0 )
  4339.     {
  4340.         DBGDASM.pc_top = address;
  4341.         DBGDASM.pc_cur = DBGDASM.pc_top;
  4342.         DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4343.     }
  4344.     edit_cmds_reset();
  4345. }
  4346.  
  4347. /**************************************************************************
  4348.  * cmd_replace_register
  4349.  * Either change a register to a specified value, change to the
  4350.  * registers window to edit a specified or (if none given) the
  4351.  * first register
  4352.  **************************************************************************/
  4353. static void cmd_replace_register( void )
  4354. {
  4355.     char *cmd = CMD;
  4356.     unsigned regnum, address;
  4357.     int length;
  4358.  
  4359.     regnum = get_register_id( &cmd, &length );
  4360.     if( regnum > 0 )
  4361.     {
  4362.         address = get_register_or_value( &cmd, &length );
  4363.         if( length )
  4364.         {
  4365.             cpu_set_reg( regnum, address );
  4366.             if( regnum > 1 )
  4367.                 dump_regs();
  4368.             else
  4369.                 /* Update in case PC changed */
  4370.                 dbg_update = 1;
  4371.         }
  4372.         else
  4373.         {
  4374.             /* Edit the first register */
  4375.             for( DBGREGS.idx = 0; DBGREGS.idx < DBGREGS.count; DBGREGS.idx++ )
  4376.                 if( DBGREGS.id[DBGREGS.idx] == regnum ) break;
  4377.             DBG.window = EDIT_REGS;
  4378.         }
  4379.     }
  4380.     else
  4381.     {
  4382.         /* Edit the first register */
  4383.         DBGREGS.idx = 0;
  4384.         DBG.window = EDIT_REGS;
  4385.     }
  4386.     edit_cmds_reset();
  4387. }
  4388.  
  4389. /**************************************************************************
  4390.  * cmd_set_memory_mode
  4391.  * Set display mode of a memory window
  4392.  **************************************************************************/
  4393. static void cmd_set_memory_mode( void )
  4394. {
  4395.     char *cmd = CMD;
  4396.     unsigned which, mode;
  4397.     int length;
  4398.  
  4399.     which = dtou( &cmd, &length );
  4400.     if( length )
  4401.     {
  4402.         which = (which - 1) % 2;
  4403.         mode = get_option_or_value( &cmd, &length, "BYTE\0WORD\0DWORD\0" );
  4404.         if( !length ) mode = 0; /* default to BYTE */
  4405.         DBGMEM[which].mode = mode;
  4406.     }
  4407.     else
  4408.     {
  4409.         DBGMEM[0].mode = 0;
  4410.         DBGMEM[1].mode = 0;
  4411.     }
  4412.     edit_cmds_reset();
  4413.     dbg_update = 1;
  4414. }
  4415.  
  4416. /**************************************************************************
  4417.  * cmd_set_dasm_relative_jumps
  4418.  * Turn display of relative jumps as $+/-offset on or off
  4419.  **************************************************************************/
  4420. static void cmd_set_dasm_relative_jumps( void )
  4421. {
  4422.     char *cmd = CMD;
  4423.  
  4424.     dbg_dasm_relative_jumps = get_boolean( &cmd, NULL );
  4425.  
  4426.     edit_cmds_reset();
  4427.     dbg_update = 1;
  4428. }
  4429.  
  4430. /**************************************************************************
  4431.  * cmd_trace_to_file
  4432.  * Turn tracing to file on or off
  4433.  * If it is to be turned on, expect filename and optionally
  4434.  * a list of register names to dump
  4435.  **************************************************************************/
  4436. static void cmd_trace_to_file( void )
  4437. {
  4438.     char *cmd = CMD;
  4439.     const char *filename;
  4440.     UINT8 regs[MAX_REGS], regcnt = 0;
  4441.     int length;
  4442.  
  4443.     filename = get_file_name( &cmd, &length );
  4444.  
  4445.     if( !my_stricmp( filename, "OFF" ) )
  4446.     {
  4447.         trace_done();
  4448.     }
  4449.     else
  4450.     {
  4451.         while( *cmd )
  4452.         {
  4453.             regs[regcnt] = get_register_id( &cmd, &length );
  4454.             if( length ) regcnt++;
  4455.         }
  4456.         regs[regcnt] = 0;
  4457.  
  4458.         trace_init( filename, regs );
  4459.     }
  4460.  
  4461.     edit_cmds_reset();
  4462. }
  4463.  
  4464. /**************************************************************************
  4465.  * cmd_dasm_up
  4466.  * Move cursor line to previous instruction
  4467.  **************************************************************************/
  4468. static void cmd_dasm_up( void )
  4469. {
  4470.     if ( (DBGDASM.pc_cur >= dasm_line( DBGDASM.pc_top, 1 ) ) &&
  4471.          ((DBGDASM.pc_cur < DBGDASM.pc_end) || (DBGDASM.pc_end < DBGDASM.pc_top)) )
  4472.     {
  4473.         unsigned dasm_pc_1st = DBGDASM.pc_top;
  4474.         unsigned dasm_pc_2nd = DBGDASM.pc_top;
  4475.         while( dasm_pc_2nd != DBGDASM.pc_end )
  4476.         {
  4477.             dasm_pc_2nd = dasm_line( dasm_pc_1st, 1 );
  4478.  
  4479.             if( dasm_pc_2nd == DBGDASM.pc_cur )
  4480.             {
  4481.                 DBGDASM.pc_cur = dasm_pc_1st;
  4482.                 dasm_pc_2nd = DBGDASM.pc_end;
  4483.             }
  4484.             else
  4485.             {
  4486.                 dasm_pc_1st = dasm_pc_2nd;
  4487.             }
  4488.         }
  4489.     }
  4490.     else
  4491.     if( DBGDASM.pc_top > 0 )
  4492.     {
  4493.         /*
  4494.          * Try to find the previous instruction by searching from the
  4495.          * longest instruction length towards the current address.
  4496.          * If we can't find one then just go back one byte,
  4497.          * which means that a previous guess was wrong.
  4498.          */
  4499.         unsigned dasm_pc_tmp = rshift(DBGDASM.pc_top - lshift(INSTL)) & AMASK;
  4500.         int i;
  4501.         for( i = 0; i < INSTL; i += ALIGN )
  4502.         {
  4503.             if( dasm_line( lshift(dasm_pc_tmp), 1 ) == DBGDASM.pc_top )
  4504.                 break;
  4505.             dasm_pc_tmp += ALIGN;
  4506.         }
  4507.         dasm_pc_tmp = lshift(dasm_pc_tmp);
  4508.         if( dasm_pc_tmp == DBGDASM.pc_top )
  4509.             dasm_pc_tmp -= ALIGN;
  4510.         DBGDASM.pc_cur = dasm_pc_tmp;
  4511.         if( DBGDASM.pc_cur < DBGDASM.pc_top )
  4512.             DBGDASM.pc_top = DBGDASM.pc_cur;
  4513.     }
  4514.     DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4515.     edit_cmds_reset();
  4516. }
  4517.  
  4518. /**************************************************************************
  4519.  * cmd_dasm_down
  4520.  * Move cursor line to next instruction
  4521.  **************************************************************************/
  4522. static void cmd_dasm_down( void )
  4523. {
  4524.     DBGDASM.pc_cur = dasm_line( DBGDASM.pc_cur, 1 );
  4525.     if( DBGDASM.pc_cur >= DBGDASM.pc_end )
  4526.           DBGDASM.pc_top = dasm_line( DBGDASM.pc_top, 1 );
  4527.     DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4528.     edit_cmds_reset();
  4529. }
  4530.  
  4531. /**************************************************************************
  4532.  * cmd_dasm_page_up
  4533.  * Disassemble previous page
  4534.  **************************************************************************/
  4535. static void cmd_dasm_page_up( void )
  4536. {
  4537.     UINT32 i;
  4538.     /*
  4539.      * This uses a 'rolling window' of start addresses to work out
  4540.      * the best address to use to generate the previous pagefull of
  4541.      * disassembly - CM 980428
  4542.      */
  4543.     if( DBGDASM.pc_top > 0 )
  4544.     {
  4545.         unsigned dasm_pc_row[50];    /* needs to be > max windows height */
  4546.         unsigned h = win_get_h(WIN_DASM(activecpu));
  4547.         unsigned dasm_pc_tmp = lshift((rshift(DBGDASM.pc_top) - h * INSTL) & AMASK);
  4548.  
  4549.         if( dasm_pc_tmp > DBGDASM.pc_top )
  4550.         {
  4551.             DBGDASM.pc_top = 0;
  4552.         }
  4553.         else
  4554.         {
  4555.             for( i= 0; dasm_pc_tmp < DBGDASM.pc_top; i++ )
  4556.             {
  4557.                 dasm_pc_row[i % h] = dasm_pc_tmp;
  4558.                 dasm_pc_tmp = dasm_line( dasm_pc_tmp, 1 );
  4559.             }
  4560.  
  4561.             /*
  4562.              * If this ever happens, it's because our
  4563.              * max_inst_len member is too small for the CPU
  4564.              */
  4565.             if( i < h )
  4566.             {
  4567.                 dasm_pc_tmp = dasm_pc_row[0];
  4568.                 win_msgbox(cur_col[E_ERROR], "DBGDASM page up",
  4569.                     "Increase cpu_intf[].max_inst_len? Line = %d\n", i);
  4570.             }
  4571.             else
  4572.             {
  4573.                 DBGDASM.pc_top = dasm_pc_row[(i + 1) % h];
  4574.             }
  4575.         }
  4576.     }
  4577.     DBGDASM.pc_cur = DBGDASM.pc_top;
  4578.     DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4579.     edit_cmds_reset();
  4580. }
  4581.  
  4582. /**************************************************************************
  4583.  * cmd_dasm_page_down
  4584.  * Disassemble next page
  4585.  **************************************************************************/
  4586. static void cmd_dasm_page_down( void )
  4587. {
  4588.     unsigned h = win_get_h(WIN_DASM(activecpu));
  4589.  
  4590.     DBGDASM.pc_top = dasm_line( DBGDASM.pc_top, h );
  4591.     DBGDASM.pc_cur = dasm_line( DBGDASM.pc_cur, h );
  4592.     DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4593.     edit_cmds_reset();
  4594. }
  4595.  
  4596. /**************************************************************************
  4597.  * cmd_dasm_home
  4598.  * Disassemble first page
  4599.  **************************************************************************/
  4600. static void cmd_dasm_home( void )
  4601. {
  4602.     DBGDASM.pc_cur = DBGDASM.pc_top = 0;
  4603.     DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4604.     edit_cmds_reset();
  4605. }
  4606.  
  4607. /**************************************************************************
  4608.  * cmd_dasm_end
  4609.  * Disassemble last page
  4610.  **************************************************************************/
  4611. static void cmd_dasm_end( void )
  4612. {
  4613.     unsigned h = win_get_h(WIN_DASM(activecpu));
  4614.     unsigned tmp_address = lshift(AMASK - h * INSTL + 1);
  4615.     unsigned end_address;
  4616.     for( ; ; )
  4617.     {
  4618.         end_address = dasm_line( tmp_address, h );
  4619.         if( end_address < tmp_address )
  4620.             break;
  4621.         tmp_address += ALIGN;
  4622.     }
  4623.     DBGDASM.pc_top = tmp_address;
  4624.     DBGDASM.pc_cur = dasm_line( DBGDASM.pc_top, h - 1 );
  4625.     DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4626.     edit_cmds_reset();
  4627. }
  4628.  
  4629. /**************************************************************************
  4630.  * cmd_brk_exec_toggle
  4631.  * Toggle execution break point at cursor line
  4632.  **************************************************************************/
  4633. static void cmd_brk_exec_toggle( void )
  4634. {
  4635.     if( DBG.brk_exec == INVALID )
  4636.     {
  4637.         DBG.brk_exec = DBGDASM.pc_cur;
  4638.         DBG.brk_exec_times = 0;
  4639.         DBG.brk_exec_reset = 0;
  4640.         dbg_update = 1;
  4641.     }
  4642.     else
  4643.     if( DBG.brk_exec == DBGDASM.pc_cur )
  4644.     {
  4645.         DBG.brk_exec = INVALID;
  4646.         DBG.brk_exec_times = 0;
  4647.         DBG.brk_exec_reset = 0;
  4648.         dbg_update = 1;
  4649.     }
  4650.     else
  4651.     {
  4652.         win_msgbox( cur_col[E_PROMPT], "Breakpoint",
  4653.             "Cleared execution break point at $%X", DBG.brk_exec );
  4654.         DBG.brk_exec = INVALID;
  4655.     }
  4656. }
  4657.  
  4658. /**************************************************************************
  4659.  * cmd_dasm_hist_follow
  4660.  * Follow the current code or data reference
  4661.  **************************************************************************/
  4662. static void cmd_dasm_hist_follow( void )
  4663. {
  4664.     unsigned i, address, access = EA_NONE;
  4665.  
  4666.     address = INVALID;
  4667.     DBGDASM.dst_ea_value = INVALID;
  4668.     DBGDASM.src_ea_value = INVALID;
  4669.  
  4670.     dasm_line( DBGDASM.pc_cur, 1 );
  4671.  
  4672.     if( DBGDASM.src_ea_value != INVALID )
  4673.     {
  4674.         access = DBGDASM.src_ea_access;
  4675.         address = DBGDASM.src_ea_value;
  4676.     }
  4677.     if( DBGDASM.dst_ea_value != INVALID )
  4678.     {
  4679.         access = DBGDASM.dst_ea_access;
  4680.         address = DBGDASM.dst_ea_value;
  4681.     }
  4682.     if( address != INVALID )
  4683.     {
  4684.         if( DBG.hist_cnt < MAX_HIST )
  4685.         {
  4686.             i = DBG.hist_cnt;
  4687.             /* Save some current values */
  4688.             DBG.hist[i].dasm_top = DBGDASM.pc_top;
  4689.             DBG.hist[i].dasm_cur = DBGDASM.pc_cur;
  4690.             DBG.hist[i].mem1_base = DBGMEM[0].base;
  4691.             DBG.hist[i].mem1_offset = DBGMEM[0].offset;
  4692.             DBG.hist[i].mem1_nibble = DBGMEM[0].nibble;
  4693.             if( access == EA_ABS_PC || access == EA_REL_PC )
  4694.             {
  4695.                 DBGDASM.pc_top = address;
  4696.                 DBGDASM.pc_cur = address;
  4697.                 DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4698.                 DBG.hist_cnt++;
  4699.             }
  4700.             else
  4701.             if( access == EA_MEM_RD || access == EA_MEM_WR || access == EA_MEM_RDWR ||
  4702.                 access == EA_ZPG_RD || access == EA_ZPG_WR || access == EA_ZPG_RDWR )
  4703.             {
  4704.                 DBGMEM[0].offset = address    % DBGMEM[0].size;
  4705.                 DBGMEM[0].base = address - DBGMEM[0].offset;
  4706.                 DBGMEM[0].nibble = 0;
  4707.                 dump_mem( 0, 0 );
  4708.                 DBG.hist_cnt++;
  4709.             }
  4710.         }
  4711.     }
  4712. }
  4713.  
  4714. /**************************************************************************
  4715.  * cmd_dasm_hist_back
  4716.  * Back to the previous point in the 'follow history'
  4717.  **************************************************************************/
  4718. static void cmd_dasm_hist_back( void )
  4719. {
  4720.     unsigned i;
  4721.     if( DBG.hist_cnt > 0)
  4722.     {
  4723.         i = --DBG.hist_cnt;
  4724.         DBGDASM.pc_top = DBG.hist[i].dasm_top;
  4725.         DBGDASM.pc_cur = DBG.hist[i].dasm_cur;
  4726.         DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4727.         DBGMEM[0].base = DBG.hist[i].mem1_base;
  4728.         DBGMEM[0].offset = DBG.hist[i].mem1_offset;
  4729.         DBGMEM[0].nibble = DBG.hist[i].mem1_nibble;
  4730.         dump_mem( 0, 0 );
  4731.     }
  4732. }
  4733.  
  4734. /**************************************************************************
  4735.  * cmd_brk_exec_toggle
  4736.  * Toggle data break point at memory location
  4737.  **************************************************************************/
  4738. static void cmd_brk_data_toggle( void )
  4739. {
  4740.     int which = DBG.window == EDIT_MEM1 ? 0 : 1;
  4741.  
  4742.     if( DBG.brk_data == INVALID )
  4743.     {
  4744.         unsigned data;
  4745.         DBG.brk_data = DBGMEM[which].address;
  4746.         data = RDMEM(DBG.brk_data);
  4747.         DBG.brk_data_oldval = data;
  4748.         DBG.brk_data_newval = INVALID;
  4749.     }
  4750.     else
  4751.     if( DBG.brk_data == DBGMEM[which].address )
  4752.     {
  4753.         DBG.brk_data = INVALID;
  4754.         DBG.brk_data_oldval = INVALID;
  4755.         DBG.brk_data_newval = INVALID;
  4756.     }
  4757.     else
  4758.     {
  4759.         win_msgbox( cur_col[E_PROMPT], "Data watchpoint",
  4760.             "Cleared data watch point at $%X", DBG.brk_data );
  4761.         DBG.brk_data = INVALID;
  4762.     }
  4763.     dbg_update = 1;
  4764.     edit_cmds_reset();
  4765. }
  4766.  
  4767. /**************************************************************************
  4768.  * cmd_run_to_cursor
  4769.  * Set temporary break point at cursor line and go
  4770.  **************************************************************************/
  4771. static void cmd_run_to_cursor( void )
  4772. {
  4773.     DBG.brk_temp = DBGDASM.pc_cur;
  4774.  
  4775.     edit_cmds_reset();
  4776.  
  4777.     cmd_go();
  4778. }
  4779.  
  4780. /**************************************************************************
  4781.  * cmd_view_screen
  4782.  * Show game screen until a key is pressed
  4783.  **************************************************************************/
  4784. static void cmd_view_screen( void )
  4785. {
  4786.     unsigned w,h;
  4787.  
  4788.     osd_get_screen_size( &w, &h );
  4789.     osd_set_display(
  4790.         Machine->scrbitmap->width,
  4791.         Machine->scrbitmap->height,
  4792.         Machine->drv->video_attributes);
  4793.  
  4794.     /* Let memory changes eventually do something to the video */
  4795.     do
  4796.     {
  4797.         draw_screen(1);
  4798.         update_video_and_audio();
  4799.     } while (keyboard_read_async() == KEYCODE_NONE);
  4800.  
  4801.     osd_set_screen_size( w, h );
  4802.     win_invalidate_video();
  4803.     win_show( WIN_REGS(activecpu) );
  4804.     win_show( WIN_DASM(activecpu) );
  4805.     win_show( WIN_MEM1(activecpu) );
  4806.     win_show( WIN_MEM2(activecpu) );
  4807.     win_show( WIN_CMDS(activecpu) );
  4808. }
  4809.  
  4810. /**************************************************************************
  4811.  * cmd_focus_next_cpu
  4812.  * Switch focus to the next CPU
  4813.  **************************************************************************/
  4814. static void cmd_focus_next_cpu( void )
  4815. {
  4816.     if( totalcpu > 1 )
  4817.     {
  4818.         win_set_title(WIN_CMDS(activecpu), "CPU #%d yield", activecpu);
  4819.         cpu_yield();
  4820.         dbg_update = 1;
  4821.         dbg_step = 1;
  4822.     }
  4823.  
  4824.     edit_cmds_reset();
  4825. }
  4826.  
  4827. /**************************************************************************
  4828.  * cmd_step
  4829.  * Step one instruction
  4830.  **************************************************************************/
  4831. static void cmd_step( void )
  4832. {
  4833.     dbg_step = 1;
  4834.     edit_cmds_reset();
  4835. }
  4836.  
  4837. /**************************************************************************
  4838.  * cmd_animate
  4839.  * Run CPU in animated mode
  4840.  **************************************************************************/
  4841. static void cmd_animate( void )
  4842. {
  4843.     char *cmd = CMD;
  4844.     unsigned data;
  4845.     int length;
  4846.     data = dtou( &cmd, &length );
  4847.     if( length )
  4848.         dbg_trace_delay = data;
  4849.  
  4850.     dbg_trace = 1;
  4851.     dbg_step = 1;
  4852.     edit_cmds_reset();
  4853. }
  4854.  
  4855. /**************************************************************************
  4856.  * cmd_step_over
  4857.  * Step over the instruction at the cursor line
  4858.  * Sets next PC and previous PS to detect a call/bsr type opcode
  4859.  * on the next entry into MAME_Debug
  4860.  **************************************************************************/
  4861. static void cmd_step_over( void )
  4862. {
  4863.     /* Set next PC to the instruction after the cursor line */
  4864.     DBG.next_pc = dasm_line( DBGDASM.pc_cur, 1 );
  4865.     DBG.prev_sp = cpu_get_sp();
  4866.     dbg_step = 1;
  4867.     edit_cmds_reset();
  4868. }
  4869.  
  4870. /**************************************************************************
  4871.  * cmd_switch_window
  4872.  * Switch back or forth to the next window:
  4873.  * commands, registers, disassembly, memory 1, memory 2
  4874.  **************************************************************************/
  4875. static void cmd_switch_window( void )
  4876. {
  4877.     if( keyboard_pressed(KEYCODE_LSHIFT) || keyboard_pressed(KEYCODE_RSHIFT) )
  4878.         DBG.window = --DBG.window % DBG_WINDOWS;
  4879.     else
  4880.         DBG.window = ++DBG.window % DBG_WINDOWS;
  4881. }
  4882.  
  4883. /**************************************************************************
  4884.  * cmd_go
  4885.  * Let the game run
  4886.  **************************************************************************/
  4887. static void cmd_go( void )
  4888. {
  4889.     debug_key_pressed = 0;
  4890.  
  4891.     dbg_update = 0;
  4892.     dbg_active = 0;
  4893.  
  4894.     edit_cmds_reset();
  4895.  
  4896.     osd_sound_enable(1);
  4897.     osd_set_display(
  4898.         Machine->scrbitmap->width,
  4899.         Machine->scrbitmap->height,
  4900.         Machine->drv->video_attributes);
  4901. }
  4902.  
  4903. /**************************************************************************
  4904.  * cmd_set_dasm_case
  4905.  * Set the case style for the disassembly window
  4906.  * "DEFAULT", "LOWER" or "UPPER" are recognized comparing the first letter
  4907.  **************************************************************************/
  4908. static void cmd_set_dasm_case( void )
  4909. {
  4910.     char *cmd = CMD;
  4911.  
  4912.     if( toupper(cmd[0]) == 'D' )
  4913.         dbg_dasm_case = 0;
  4914.     else
  4915.     if( toupper(cmd[0]) == 'L' )
  4916.         dbg_dasm_case = 1;
  4917.     else
  4918.     if( toupper(cmd[0]) == 'U' )
  4919.         dbg_dasm_case = 2;
  4920.     else
  4921.         dbg_dasm_case = xtou( &cmd, NULL );
  4922.  
  4923.     edit_cmds_reset();
  4924.     dbg_update = 1;
  4925. }
  4926.  
  4927. /**************************************************************************
  4928.  * cmd_set_mem_squeezed
  4929.  * Set allow squeezed memory display
  4930.  **************************************************************************/
  4931. static void cmd_set_mem_squeezed( void )
  4932. {
  4933.     char *cmd = CMD;
  4934.  
  4935.     dbg_mem_squeezed = get_boolean( &cmd, NULL );
  4936.  
  4937.     edit_cmds_reset();
  4938.     dbg_update = 1;
  4939. }
  4940.  
  4941. /**************************************************************************
  4942.  * cmd_set_dasm_opcodes
  4943.  * Set allow squeezed memory display
  4944.  **************************************************************************/
  4945. static void cmd_set_dasm_opcodes( void )
  4946. {
  4947.     char *cmd = CMD;
  4948.     UINT32 win = WIN_DASM(activecpu);
  4949.     UINT32 w = win_get_w( win );
  4950.     UINT32 dw = (INSTL / ALIGN) * (ALIGN * 2 + 1);
  4951.     int state;
  4952.  
  4953.     state = get_boolean( &cmd, NULL );
  4954.  
  4955.     if( dbg_dasm_opcodes != state )
  4956.     {
  4957.         dbg_dasm_opcodes = state;
  4958.         if( state )
  4959.         {
  4960.             win_set_prio( win, 0 );
  4961.             win_set_w( win, w + dw  );
  4962.         }
  4963.         else
  4964.         {
  4965.             win_set_prio( win, 1 );
  4966.             win_set_w( win, w - dw );
  4967.         }
  4968.         DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  4969.     }
  4970.  
  4971.     edit_cmds_reset();
  4972.     dbg_update = 1;
  4973. }
  4974.  
  4975. static void mame_debug_reset_statics( void )
  4976. {
  4977.     /* Reset the statics */
  4978.     memset( &dbg, 0, sizeof(dbg) );
  4979.  
  4980.     activecpu = INVALID;
  4981.     previous_activecpu = INVALID;
  4982.     totalcpu = 0;
  4983.     cputype = 0;
  4984.  
  4985.     dbg_fast = 0;
  4986.     dbg_step = 0;
  4987.     dbg_trace = 0;
  4988.     dbg_update = 0;
  4989.     dbg_update_cur = 0;
  4990.     dbg_active = 0;
  4991.     dbg_mem_squeezed = 0;
  4992.     dbg_dasm_opcodes = 0;
  4993.     dbg_dasm_case = 0;
  4994.     dbg_dasm_relative_jumps = 0;
  4995.     dbg_info_once = NULL;
  4996. }
  4997.  
  4998.  
  4999. /**************************************************************************
  5000.  *    mame_debug_init
  5001.  *    This function is called from cpu_run to startup the debugger
  5002.  **************************************************************************/
  5003. void mame_debug_init(void)
  5004. {
  5005.     char filename[127+1];
  5006.     FILE *file;
  5007.  
  5008.     mame_debug_reset_statics();
  5009.     osd_set_screen_size( 80, 25 );
  5010.  
  5011.     totalcpu = cpu_gettotalcpu();
  5012.  
  5013.     for( activecpu = 0; activecpu < totalcpu; activecpu++ )
  5014.     {
  5015.         DBG.window = EDIT_CMDS;
  5016.         DBG.brk_exec = INVALID;
  5017.         DBG.brk_exec_times = 0;
  5018.         DBG.brk_exec_reset = 0;
  5019.         DBG.brk_data = INVALID;
  5020.         DBG.brk_data_oldval = INVALID;
  5021.         DBG.brk_data_newval = INVALID;
  5022.         DBG.brk_regs = INVALID;
  5023.         DBG.brk_regs_oldval = INVALID;
  5024.         DBG.brk_regs_newval = INVALID;
  5025.         DBG.brk_regs_mask = 0xffffffff;
  5026.         DBG.brk_temp = INVALID;
  5027.         DBGMEM[0].base = 0x0000;
  5028.         DBGMEM[1].base = 1 << (ABITS / 2);
  5029.         switch( cpunum_align_unit(activecpu) )
  5030.         {
  5031.             case 1: DBGMEM[0].mode = DBGMEM[1].mode = MODE_HEX_UINT8;  break;
  5032.             case 2: DBGMEM[0].mode = DBGMEM[1].mode = MODE_HEX_UINT16; break;
  5033.             case 4: DBGMEM[0].mode = DBGMEM[1].mode = MODE_HEX_UINT32; break;
  5034.         }
  5035.     }
  5036.  
  5037.     /* create windows for the active CPU */
  5038.     dbg_open_windows();
  5039.  
  5040.     /* See if there is an existing global mamedbg config file */
  5041.     strcpy( filename, "mamedbg.cfg" );
  5042.     file = fopen( filename, "r" );
  5043.     if( file )
  5044.     {
  5045.         char *cmdline = CMD, *p;
  5046.         int cmd;
  5047.  
  5048.         while( !feof(file) )
  5049.         {
  5050.             fgets( cmdline, 80, file );
  5051.             cmdline[80] = '\0';
  5052.             if( *cmdline == ';' || *cmdline == '#' )
  5053.                 continue;
  5054.             p = strchr( cmdline, '\r' );
  5055.             if( p ) *p = '\0';
  5056.             p = strchr( cmdline, '\n' );
  5057.             if( p ) *p = '\0';
  5058.             /* Make it all upper case */
  5059.             strcpy( cmdline, upper(cmdline) );
  5060.             cmd = edit_cmds_parse( cmdline );
  5061.             if( cmd != INVALID && commands[cmd].function )
  5062.                 (*commands[cmd].function)();
  5063.         }
  5064.         fclose(file);
  5065.     }
  5066.     for( activecpu = 0; activecpu < totalcpu; activecpu++ )
  5067.     {
  5068.         /* See if there is an existing startup file <game>.cf<cpunum> */
  5069.         sprintf( filename, "%s.cf%d", Machine->gamedrv->name, activecpu );
  5070.         file = fopen( filename, "r" );
  5071.         if( file )
  5072.         {
  5073.             char *cmdline = CMD, *p;
  5074.             int cmd;
  5075.  
  5076.             while( !feof(file) )
  5077.             {
  5078.                 fgets( cmdline, 80, file );
  5079.                 cmdline[80] = '\0';
  5080.                 if( *cmdline == ';' || *cmdline == '#' )
  5081.                     continue;
  5082.                 p = strchr( cmdline, '\r' );
  5083.                 if( p ) *p = '\0';
  5084.                 p = strchr( cmdline, '\n' );
  5085.                 if( p ) *p = '\0';
  5086.                 /* Make it all upper case */
  5087.                 strcpy( cmdline, upper(cmdline) );
  5088.                 cmd = edit_cmds_parse( cmdline );
  5089.                 if( cmd != INVALID && commands[cmd].function )
  5090.                     (*commands[cmd].function)();
  5091.             }
  5092.             fclose(file);
  5093.         }
  5094.     }
  5095.  
  5096.     debug_key_pressed = 1;
  5097.  
  5098.     first_time = 1;
  5099. }
  5100.  
  5101. /**************************************************************************
  5102.  *    mame_debug_exit
  5103.  *    This function is called from cpu_run to shutdown the debugger
  5104.  **************************************************************************/
  5105. void mame_debug_exit(void)
  5106. {
  5107.     dbg_close_windows();
  5108.     mame_debug_reset_statics();
  5109. }
  5110.  
  5111. /**************************************************************************
  5112.  **************************************************************************
  5113.  *      MAME_Debug
  5114.  *      This function is called from within an execution loop of a
  5115.  *      CPU core whenever mame_debug is non zero
  5116.  **************************************************************************
  5117.  **************************************************************************/
  5118. void MAME_Debug(void)
  5119. {
  5120.     if( ++debug_key_delay == 0x7fff )
  5121.     {
  5122.         debug_key_delay = 0;
  5123.         debug_key_pressed = seq_pressed(input_port_type_seq(IPT_UI_ON_SCREEN_DISPLAY));
  5124.     }
  5125.  
  5126.     if( dbg_fast )
  5127.     {
  5128.         if( !debug_key_pressed ) return;
  5129.         dbg_fast = 0;
  5130.     }
  5131.  
  5132.     activecpu = cpu_getactivecpu();
  5133.  
  5134.     /* If this CPU shall be ignore, just return */
  5135.     if( DBG.ignore ) return;
  5136.  
  5137.     cputype = Machine->drv->cpu[activecpu].cpu_type & ~CPU_FLAGS_MASK;
  5138.  
  5139.     if( trace_on )
  5140.     {
  5141.         trace_select();
  5142.         trace_output();
  5143.     }
  5144.  
  5145.     if( DBG.prev_sp )
  5146.     {
  5147.         /* assume we're in debug */
  5148.         dbg_active = 1;
  5149.         /* See if we went into a function.
  5150.            A 'return' will cause the CPU's stack pointer to be
  5151.            greater than the previous stack pointer */
  5152.         if( cpu_get_pc() != DBG.next_pc && cpu_get_sp() < DBG.prev_sp )
  5153.         {
  5154.             /* if so, set the temporary breakpoint on the return PC */
  5155.             DBG.brk_temp = DBG.next_pc;
  5156.             dbg_update = 0;
  5157.             dbg_active = 0;
  5158.             osd_sound_enable(1);
  5159.             osd_set_display(
  5160.                 Machine->scrbitmap->width,
  5161.                 Machine->scrbitmap->height,
  5162.                 Machine->drv->video_attributes);
  5163.         }
  5164.         DBG.prev_sp = 0;
  5165.     }
  5166.  
  5167.     if ( (first_time || hit_brk_exec() || hit_brk_data() || hit_brk_regs() || debug_key_pressed) && !dbg_active )
  5168.     {
  5169.         clock_t curr = clock();
  5170.         unsigned w, h;
  5171.  
  5172.         debug_key_pressed = 0;
  5173.  
  5174.         if( !first_time )
  5175.         {
  5176.             osd_sound_enable(0);
  5177.             do
  5178.             {
  5179.                 update_video_and_audio();    /* give time to the sound hardware to apply the volume change */
  5180.             } while( (clock() - curr) < (CLOCKS_PER_SEC / 15) );
  5181.         }
  5182.  
  5183.         first_time = 0;
  5184.         osd_get_screen_size( &w, &h );
  5185.         osd_set_screen_size( w, h );
  5186.         win_invalidate_video();
  5187.  
  5188.         edit_cmds_reset();
  5189.  
  5190.         DBG.brk_temp = INVALID;
  5191.         dbg_active = 1;
  5192.         dbg_update_cur = 1;
  5193.         dbg_trace = 0;
  5194.     }
  5195.  
  5196.     if( dbg_step )
  5197.     {
  5198.         DBGDASM.pc_cur = cpu_get_pc();
  5199.         dbg_step = 0;
  5200.     }
  5201.  
  5202.     /* Assume we need to update the windows */
  5203.     dbg_update = 1;
  5204.  
  5205.     while( dbg_active && !dbg_step )
  5206.     {
  5207.         if( dbg_trace )
  5208.         {
  5209.             static int trace_delay;
  5210.             dbg_step = 1;
  5211.             if( ++trace_delay < dbg_trace_delay )
  5212.             {
  5213.                 dbg_update = 0;
  5214.             }
  5215.             else
  5216.             {
  5217.                 trace_delay = 0;
  5218.  
  5219.                 if( keyboard_pressed(KEYCODE_SPACE) )
  5220.                 {
  5221.                     dbg_trace = 0;
  5222.                     dbg_step = 0;
  5223.                 }
  5224.             }
  5225.         }
  5226.  
  5227.         if( dbg_update )
  5228.         {
  5229.             if( activecpu != previous_activecpu )
  5230.             {
  5231.                 if( previous_activecpu != INVALID )
  5232.                 {
  5233.                     win_hide( WIN_REGS(previous_activecpu) );
  5234.                     win_hide( WIN_DASM(previous_activecpu) );
  5235.                     win_hide( WIN_MEM1(previous_activecpu) );
  5236.                     win_hide( WIN_MEM2(previous_activecpu) );
  5237.                     win_hide( WIN_CMDS(previous_activecpu) );
  5238.                 }
  5239.                 win_show( WIN_REGS(activecpu) );
  5240.                 win_show( WIN_DASM(activecpu) );
  5241.                 win_show( WIN_MEM1(activecpu) );
  5242.                 win_show( WIN_MEM2(activecpu) );
  5243.                 win_show( WIN_CMDS(activecpu) );
  5244.             }
  5245.  
  5246.             dump_regs();
  5247.             dump_mem( 0, DBG.window != EDIT_MEM1 );
  5248.             dump_mem( 1, DBG.window != EDIT_MEM2 );
  5249.             DBGDASM.pc_cpu = cpu_get_pc();
  5250.             /* Check if pc_cpu is outside of our disassembly window */
  5251.             if( DBGDASM.pc_cpu < DBGDASM.pc_top || DBGDASM.pc_cpu >= DBGDASM.pc_end )
  5252.                 DBGDASM.pc_top = DBGDASM.pc_cpu;
  5253.             DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  5254.             if( DBGDASM.pc_cur < DBGDASM.pc_top || DBGDASM.pc_cur >= DBGDASM.pc_end || dbg_update_cur )
  5255.             {
  5256.                 DBGDASM.pc_cur = DBGDASM.pc_cpu;
  5257.                 DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
  5258.                 dbg_update_cur = 0;
  5259.             }
  5260.             osd_screen_update();
  5261.             dbg_update = 0;
  5262.         }
  5263.  
  5264.         if( !dbg_trace )
  5265.         {
  5266.             switch( DBG.window )
  5267.             {
  5268.                 case EDIT_REGS: edit_regs(); break;
  5269.                 case EDIT_DASM: edit_dasm(); break;
  5270.                 case EDIT_MEM1: edit_mem(0); break;
  5271.                 case EDIT_MEM2: edit_mem(1); break;
  5272.                 case EDIT_CMDS: edit_cmds(); break;
  5273.             }
  5274.         }
  5275.     }
  5276.  
  5277.     /* update backup copies of memory and registers */
  5278.     if( DBGMEM[0].changed )
  5279.     {
  5280.         DBGMEM[0].changed = 0;
  5281.         memcpy( DBGMEM[0].backup,
  5282.                 DBGMEM[0].newval, DBGMEM[0].size );
  5283.     }
  5284.     if( DBGMEM[1].changed )
  5285.     {
  5286.         DBGMEM[1].changed = 0;
  5287.         memcpy( DBGMEM[1].backup,
  5288.                 DBGMEM[1].newval, DBGMEM[0].size );
  5289.     }
  5290.     if( DBGREGS.changed )
  5291.     {
  5292.         DBGREGS.changed = 0;
  5293.         memcpy( DBGREGS.backup,
  5294.                 DBGREGS.newval, DBGREGS.count * sizeof(UINT32) );
  5295.     }
  5296. }
  5297.  
  5298. #endif
  5299.  
  5300.